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; 2366 `NULL` if unneeded 2367 2368 Level: advanced 2369 2370 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2371 `PetscViewer`, `PetscSF` 2372 @*/ 2373 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2374 { 2375 PetscBool ishdf5; 2376 2377 PetscFunctionBegin; 2378 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2379 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2380 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2381 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2382 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2383 if (ishdf5) { 2384 #if defined(PETSC_HAVE_HDF5) 2385 PetscViewerFormat format; 2386 PetscCall(PetscViewerGetFormat(viewer, &format)); 2387 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2388 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2389 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2390 #else 2391 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2392 #endif 2393 } 2394 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2395 PetscFunctionReturn(PETSC_SUCCESS); 2396 } 2397 2398 /*@ 2399 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2400 2401 Collective 2402 2403 Input Parameters: 2404 + dm - The `DM` into which the coordinates are loaded 2405 . viewer - The `PetscViewer` for the saved coordinates 2406 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2407 2408 Level: advanced 2409 2410 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2411 `PetscSF`, `PetscViewer` 2412 @*/ 2413 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2414 { 2415 PetscBool ishdf5; 2416 2417 PetscFunctionBegin; 2418 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2419 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2420 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2421 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2422 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2423 if (ishdf5) { 2424 #if defined(PETSC_HAVE_HDF5) 2425 PetscViewerFormat format; 2426 PetscCall(PetscViewerGetFormat(viewer, &format)); 2427 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2428 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2429 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2430 #else 2431 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2432 #endif 2433 } 2434 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2435 PetscFunctionReturn(PETSC_SUCCESS); 2436 } 2437 2438 /*@ 2439 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2440 2441 Collective 2442 2443 Input Parameters: 2444 + dm - The `DM` into which the labels are loaded 2445 . viewer - The `PetscViewer` for the saved labels 2446 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2447 2448 Level: advanced 2449 2450 Note: 2451 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2452 2453 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2454 `PetscSF`, `PetscViewer` 2455 @*/ 2456 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2457 { 2458 PetscBool ishdf5; 2459 2460 PetscFunctionBegin; 2461 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2462 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2463 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2464 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2465 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2466 if (ishdf5) { 2467 #if defined(PETSC_HAVE_HDF5) 2468 PetscViewerFormat format; 2469 2470 PetscCall(PetscViewerGetFormat(viewer, &format)); 2471 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2472 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2473 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2474 #else 2475 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2476 #endif 2477 } 2478 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2479 PetscFunctionReturn(PETSC_SUCCESS); 2480 } 2481 2482 /*@ 2483 DMPlexSectionLoad - Loads section into a `DMPLEX` 2484 2485 Collective 2486 2487 Input Parameters: 2488 + dm - The `DM` that represents the topology 2489 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2490 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2491 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2492 2493 Output Parameters: 2494 + 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) 2495 - 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) 2496 2497 Level: advanced 2498 2499 Notes: 2500 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. 2501 2502 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. 2503 2504 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. 2505 2506 Example using 2 processes: 2507 .vb 2508 NX (number of points on dm): 4 2509 sectionA : the on-disk section 2510 vecA : a vector associated with sectionA 2511 sectionB : sectiondm's local section constructed in this function 2512 vecB (local) : a vector associated with sectiondm's local section 2513 vecB (global) : a vector associated with sectiondm's global section 2514 2515 rank 0 rank 1 2516 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2517 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2518 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2519 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2520 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2521 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2522 sectionB->atlasDof : 1 0 1 | 1 3 2523 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2524 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2525 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2526 .ve 2527 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2528 2529 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2530 @*/ 2531 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2532 { 2533 PetscBool ishdf5; 2534 2535 PetscFunctionBegin; 2536 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2537 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2538 if (!sectiondm) sectiondm = dm; 2539 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2540 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2541 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2542 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2543 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2544 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2545 if (ishdf5) { 2546 #if defined(PETSC_HAVE_HDF5) 2547 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2548 #else 2549 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2550 #endif 2551 } 2552 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2553 PetscFunctionReturn(PETSC_SUCCESS); 2554 } 2555 2556 /*@ 2557 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2558 2559 Collective 2560 2561 Input Parameters: 2562 + dm - The `DM` that represents the topology 2563 . viewer - The `PetscViewer` that represents the on-disk vector data 2564 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2565 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2566 - vec - The global vector to set values of 2567 2568 Level: advanced 2569 2570 Notes: 2571 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. 2572 2573 Calling sequence: 2574 .vb 2575 DMCreate(PETSC_COMM_WORLD, &dm); 2576 DMSetType(dm, DMPLEX); 2577 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2578 DMPlexTopologyLoad(dm, viewer, &sfX); 2579 DMClone(dm, §iondm); 2580 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2581 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2582 DMGetGlobalVector(sectiondm, &vec); 2583 PetscObjectSetName((PetscObject)vec, "vec_name"); 2584 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2585 DMRestoreGlobalVector(sectiondm, &vec); 2586 PetscSFDestroy(&gsf); 2587 PetscSFDestroy(&sfX); 2588 DMDestroy(§iondm); 2589 DMDestroy(&dm); 2590 .ve 2591 2592 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2593 `PetscSF`, `PetscViewer` 2594 @*/ 2595 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2596 { 2597 PetscBool ishdf5; 2598 2599 PetscFunctionBegin; 2600 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2601 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2602 if (!sectiondm) sectiondm = dm; 2603 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2604 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2605 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2606 /* Check consistency */ 2607 { 2608 PetscSection section; 2609 PetscBool includesConstraints; 2610 PetscInt m, m1; 2611 2612 PetscCall(VecGetLocalSize(vec, &m1)); 2613 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2614 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2615 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2616 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2617 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2618 } 2619 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2620 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2621 if (ishdf5) { 2622 #if defined(PETSC_HAVE_HDF5) 2623 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2624 #else 2625 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2626 #endif 2627 } 2628 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2629 PetscFunctionReturn(PETSC_SUCCESS); 2630 } 2631 2632 /*@ 2633 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2634 2635 Collective 2636 2637 Input Parameters: 2638 + dm - The `DM` that represents the topology 2639 . viewer - The `PetscViewer` that represents the on-disk vector data 2640 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2641 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2642 - vec - The local vector to set values of 2643 2644 Level: advanced 2645 2646 Notes: 2647 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. 2648 2649 Calling sequence: 2650 .vb 2651 DMCreate(PETSC_COMM_WORLD, &dm); 2652 DMSetType(dm, DMPLEX); 2653 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2654 DMPlexTopologyLoad(dm, viewer, &sfX); 2655 DMClone(dm, §iondm); 2656 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2657 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2658 DMGetLocalVector(sectiondm, &vec); 2659 PetscObjectSetName((PetscObject)vec, "vec_name"); 2660 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2661 DMRestoreLocalVector(sectiondm, &vec); 2662 PetscSFDestroy(&lsf); 2663 PetscSFDestroy(&sfX); 2664 DMDestroy(§iondm); 2665 DMDestroy(&dm); 2666 .ve 2667 2668 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2669 `PetscSF`, `PetscViewer` 2670 @*/ 2671 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2672 { 2673 PetscBool ishdf5; 2674 2675 PetscFunctionBegin; 2676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2677 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2678 if (!sectiondm) sectiondm = dm; 2679 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2680 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2681 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2682 /* Check consistency */ 2683 { 2684 PetscSection section; 2685 PetscBool includesConstraints; 2686 PetscInt m, m1; 2687 2688 PetscCall(VecGetLocalSize(vec, &m1)); 2689 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2690 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2691 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2692 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2693 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2694 } 2695 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2696 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2697 if (ishdf5) { 2698 #if defined(PETSC_HAVE_HDF5) 2699 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2700 #else 2701 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2702 #endif 2703 } 2704 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2705 PetscFunctionReturn(PETSC_SUCCESS); 2706 } 2707 2708 PetscErrorCode DMDestroy_Plex(DM dm) 2709 { 2710 DM_Plex *mesh = (DM_Plex *)dm->data; 2711 2712 PetscFunctionBegin; 2713 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2714 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2715 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2716 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2717 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2718 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2719 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2720 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2721 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2722 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2723 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2724 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2725 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2726 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2727 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2728 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2729 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2730 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2731 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2732 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2733 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2734 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2735 PetscCall(PetscFree(mesh->cones)); 2736 PetscCall(PetscFree(mesh->coneOrientations)); 2737 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2738 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2739 PetscCall(PetscFree(mesh->supports)); 2740 PetscCall(PetscFree(mesh->cellTypes)); 2741 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2742 PetscCall(PetscFree(mesh->tetgenOpts)); 2743 PetscCall(PetscFree(mesh->triangleOpts)); 2744 PetscCall(PetscFree(mesh->transformType)); 2745 PetscCall(PetscFree(mesh->distributionName)); 2746 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2747 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2748 PetscCall(ISDestroy(&mesh->subpointIS)); 2749 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2750 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2751 if (mesh->periodic.face_sfs) { 2752 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2753 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2754 } 2755 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2756 if (mesh->periodic.periodic_points) { 2757 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2758 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2759 } 2760 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2761 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2762 PetscCall(ISDestroy(&mesh->anchorIS)); 2763 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2764 PetscCall(PetscFree(mesh->parents)); 2765 PetscCall(PetscFree(mesh->childIDs)); 2766 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2767 PetscCall(PetscFree(mesh->children)); 2768 PetscCall(DMDestroy(&mesh->referenceTree)); 2769 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2770 PetscCall(PetscFree(mesh->neighbors)); 2771 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2772 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2773 PetscCall(PetscFree(mesh)); 2774 PetscFunctionReturn(PETSC_SUCCESS); 2775 } 2776 2777 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2778 { 2779 PetscSection sectionGlobal, sectionLocal; 2780 PetscInt bs = -1, mbs; 2781 PetscInt localSize, localStart = 0; 2782 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2783 MatType mtype; 2784 ISLocalToGlobalMapping ltog; 2785 2786 PetscFunctionBegin; 2787 PetscCall(MatInitializePackage()); 2788 mtype = dm->mattype; 2789 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2790 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2791 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2792 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2793 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2794 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2795 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2796 PetscCall(MatSetType(*J, mtype)); 2797 PetscCall(MatSetFromOptions(*J)); 2798 PetscCall(MatGetBlockSize(*J, &mbs)); 2799 if (mbs > 1) bs = mbs; 2800 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2801 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2802 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2803 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2804 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2805 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2806 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2807 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2808 if (!isShell) { 2809 // There are three states with pblocks, since block starts can have no dofs: 2810 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2811 // TRUE) Block Start: The first entry in a block has been added 2812 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2813 PetscBT blst; 2814 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2815 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2816 const PetscInt *perm = NULL; 2817 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2818 PetscInt pStart, pEnd, dof, cdof, num_fields; 2819 2820 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2821 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2822 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2823 2824 PetscCall(PetscCalloc1(localSize, &pblocks)); 2825 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2826 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2827 // We need to process in the permuted order to get block sizes right 2828 for (PetscInt point = pStart; point < pEnd; ++point) { 2829 const PetscInt p = perm ? perm[point] : point; 2830 2831 switch (dm->blocking_type) { 2832 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2833 PetscInt bdof, offset; 2834 2835 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2836 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2837 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2838 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2839 if (dof > 0) { 2840 // State change 2841 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2842 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2843 2844 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2845 // Signal block concatenation 2846 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2847 } 2848 dof = dof < 0 ? -(dof + 1) : dof; 2849 bdof = cdof && (dof - cdof) ? 1 : dof; 2850 if (dof) { 2851 if (bs < 0) { 2852 bs = bdof; 2853 } else if (bs != bdof) { 2854 bs = 1; 2855 } 2856 } 2857 } break; 2858 case DM_BLOCKING_FIELD_NODE: { 2859 for (PetscInt field = 0; field < num_fields; field++) { 2860 PetscInt num_comp, bdof, offset; 2861 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2862 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2863 if (dof < 0) continue; 2864 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2865 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2866 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); 2867 PetscInt num_nodes = dof / num_comp; 2868 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2869 // Handle possibly constant block size (unlikely) 2870 bdof = cdof && (dof - cdof) ? 1 : dof; 2871 if (dof) { 2872 if (bs < 0) { 2873 bs = bdof; 2874 } else if (bs != bdof) { 2875 bs = 1; 2876 } 2877 } 2878 } 2879 } break; 2880 } 2881 } 2882 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2883 /* Must have same blocksize on all procs (some might have no points) */ 2884 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2885 bsLocal[1] = bs; 2886 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2887 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2888 else bs = bsMinMax[0]; 2889 bs = PetscMax(1, bs); 2890 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2891 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2892 PetscCall(MatSetBlockSize(*J, bs)); 2893 PetscCall(MatSetUp(*J)); 2894 } else { 2895 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2896 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2897 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2898 } 2899 if (pblocks) { // Consolidate blocks 2900 PetscInt nblocks = 0; 2901 pblocks[0] = PetscAbs(pblocks[0]); 2902 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2903 if (pblocks[i] == 0) continue; 2904 // Negative block size indicates the blocks should be concatenated 2905 if (pblocks[i] < 0) { 2906 pblocks[i] = -pblocks[i]; 2907 pblocks[nblocks - 1] += pblocks[i]; 2908 } else { 2909 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2910 } 2911 for (PetscInt j = 1; j < pblocks[i]; j++) 2912 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); 2913 } 2914 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2915 } 2916 PetscCall(PetscFree(pblocks)); 2917 } 2918 PetscCall(MatSetDM(*J, dm)); 2919 PetscFunctionReturn(PETSC_SUCCESS); 2920 } 2921 2922 /*@ 2923 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2924 2925 Not Collective 2926 2927 Input Parameter: 2928 . dm - The `DMPLEX` 2929 2930 Output Parameter: 2931 . subsection - The subdomain section 2932 2933 Level: developer 2934 2935 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2936 @*/ 2937 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2938 { 2939 DM_Plex *mesh = (DM_Plex *)dm->data; 2940 2941 PetscFunctionBegin; 2942 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2943 if (!mesh->subdomainSection) { 2944 PetscSection section; 2945 PetscSF sf; 2946 2947 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2948 PetscCall(DMGetLocalSection(dm, §ion)); 2949 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2950 PetscCall(PetscSFDestroy(&sf)); 2951 } 2952 *subsection = mesh->subdomainSection; 2953 PetscFunctionReturn(PETSC_SUCCESS); 2954 } 2955 2956 /*@ 2957 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2958 2959 Not Collective 2960 2961 Input Parameter: 2962 . dm - The `DMPLEX` 2963 2964 Output Parameters: 2965 + pStart - The first mesh point 2966 - pEnd - The upper bound for mesh points 2967 2968 Level: beginner 2969 2970 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2971 @*/ 2972 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2973 { 2974 DM_Plex *mesh = (DM_Plex *)dm->data; 2975 2976 PetscFunctionBegin; 2977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2978 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2979 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2980 PetscFunctionReturn(PETSC_SUCCESS); 2981 } 2982 2983 /*@ 2984 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2985 2986 Not Collective 2987 2988 Input Parameters: 2989 + dm - The `DMPLEX` 2990 . pStart - The first mesh point 2991 - pEnd - The upper bound for mesh points 2992 2993 Level: beginner 2994 2995 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2996 @*/ 2997 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2998 { 2999 DM_Plex *mesh = (DM_Plex *)dm->data; 3000 3001 PetscFunctionBegin; 3002 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3003 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3004 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3005 PetscCall(PetscFree(mesh->cellTypes)); 3006 PetscFunctionReturn(PETSC_SUCCESS); 3007 } 3008 3009 /*@ 3010 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3011 3012 Not Collective 3013 3014 Input Parameters: 3015 + dm - The `DMPLEX` 3016 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3017 3018 Output Parameter: 3019 . size - The cone size for point `p` 3020 3021 Level: beginner 3022 3023 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3024 @*/ 3025 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3026 { 3027 DM_Plex *mesh = (DM_Plex *)dm->data; 3028 3029 PetscFunctionBegin; 3030 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3031 PetscAssertPointer(size, 3); 3032 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3033 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3034 PetscFunctionReturn(PETSC_SUCCESS); 3035 } 3036 3037 /*@ 3038 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3039 3040 Not Collective 3041 3042 Input Parameters: 3043 + dm - The `DMPLEX` 3044 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3045 - size - The cone size for point `p` 3046 3047 Level: beginner 3048 3049 Note: 3050 This should be called after `DMPlexSetChart()`. 3051 3052 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3053 @*/ 3054 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3055 { 3056 DM_Plex *mesh = (DM_Plex *)dm->data; 3057 3058 PetscFunctionBegin; 3059 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3060 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3061 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3062 PetscFunctionReturn(PETSC_SUCCESS); 3063 } 3064 3065 /*@C 3066 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3067 3068 Not Collective 3069 3070 Input Parameters: 3071 + dm - The `DMPLEX` 3072 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3073 3074 Output Parameter: 3075 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3076 3077 Level: beginner 3078 3079 Fortran Notes: 3080 `cone` must be declared with 3081 .vb 3082 PetscInt, pointer :: cone(:) 3083 .ve 3084 3085 You must also call `DMPlexRestoreCone()` after you finish using the array. 3086 `DMPlexRestoreCone()` is not needed/available in C. 3087 3088 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3089 @*/ 3090 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3091 { 3092 DM_Plex *mesh = (DM_Plex *)dm->data; 3093 PetscInt off; 3094 3095 PetscFunctionBegin; 3096 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3097 PetscAssertPointer(cone, 3); 3098 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3099 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3100 PetscFunctionReturn(PETSC_SUCCESS); 3101 } 3102 3103 /*@ 3104 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3105 3106 Not Collective 3107 3108 Input Parameters: 3109 + dm - The `DMPLEX` 3110 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3111 3112 Output Parameters: 3113 + pConesSection - `PetscSection` describing the layout of `pCones` 3114 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3115 3116 Level: intermediate 3117 3118 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3119 @*/ 3120 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3121 { 3122 PetscSection cs, newcs; 3123 PetscInt *cones; 3124 PetscInt *newarr = NULL; 3125 PetscInt n; 3126 3127 PetscFunctionBegin; 3128 PetscCall(DMPlexGetCones(dm, &cones)); 3129 PetscCall(DMPlexGetConeSection(dm, &cs)); 3130 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3131 if (pConesSection) *pConesSection = newcs; 3132 if (pCones) { 3133 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3134 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3135 } 3136 PetscFunctionReturn(PETSC_SUCCESS); 3137 } 3138 3139 /*@ 3140 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3141 3142 Not Collective 3143 3144 Input Parameters: 3145 + dm - The `DMPLEX` 3146 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3147 3148 Output Parameter: 3149 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3150 3151 Level: advanced 3152 3153 Notes: 3154 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3155 3156 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3157 3158 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3159 `DMPlexGetDepth()`, `IS` 3160 @*/ 3161 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3162 { 3163 IS *expandedPointsAll; 3164 PetscInt depth; 3165 3166 PetscFunctionBegin; 3167 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3168 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3169 PetscAssertPointer(expandedPoints, 3); 3170 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3171 *expandedPoints = expandedPointsAll[0]; 3172 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3173 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3174 PetscFunctionReturn(PETSC_SUCCESS); 3175 } 3176 3177 /*@ 3178 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3179 (DAG points of depth 0, i.e., without cones). 3180 3181 Not Collective 3182 3183 Input Parameters: 3184 + dm - The `DMPLEX` 3185 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3186 3187 Output Parameters: 3188 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3189 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3190 - sections - (optional) An array of sections which describe mappings from points to their cone points 3191 3192 Level: advanced 3193 3194 Notes: 3195 Like `DMPlexGetConeTuple()` but recursive. 3196 3197 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. 3198 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3199 3200 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\: 3201 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3202 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3203 3204 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3205 `DMPlexGetDepth()`, `PetscSection`, `IS` 3206 @*/ 3207 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3208 { 3209 const PetscInt *arr0 = NULL, *cone = NULL; 3210 PetscInt *arr = NULL, *newarr = NULL; 3211 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3212 IS *expandedPoints_; 3213 PetscSection *sections_; 3214 3215 PetscFunctionBegin; 3216 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3217 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3218 if (depth) PetscAssertPointer(depth, 3); 3219 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3220 if (sections) PetscAssertPointer(sections, 5); 3221 PetscCall(ISGetLocalSize(points, &n)); 3222 PetscCall(ISGetIndices(points, &arr0)); 3223 PetscCall(DMPlexGetDepth(dm, &depth_)); 3224 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3225 PetscCall(PetscCalloc1(depth_, §ions_)); 3226 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3227 for (d = depth_ - 1; d >= 0; d--) { 3228 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3229 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3230 for (i = 0; i < n; i++) { 3231 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3232 if (arr[i] >= start && arr[i] < end) { 3233 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3234 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3235 } else { 3236 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3237 } 3238 } 3239 PetscCall(PetscSectionSetUp(sections_[d])); 3240 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3241 PetscCall(PetscMalloc1(newn, &newarr)); 3242 for (i = 0; i < n; i++) { 3243 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3244 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3245 if (cn > 1) { 3246 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3247 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3248 } else { 3249 newarr[co] = arr[i]; 3250 } 3251 } 3252 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3253 arr = newarr; 3254 n = newn; 3255 } 3256 PetscCall(ISRestoreIndices(points, &arr0)); 3257 *depth = depth_; 3258 if (expandedPoints) *expandedPoints = expandedPoints_; 3259 else { 3260 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3261 PetscCall(PetscFree(expandedPoints_)); 3262 } 3263 if (sections) *sections = sections_; 3264 else { 3265 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3266 PetscCall(PetscFree(sections_)); 3267 } 3268 PetscFunctionReturn(PETSC_SUCCESS); 3269 } 3270 3271 /*@ 3272 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3273 3274 Not Collective 3275 3276 Input Parameters: 3277 + dm - The `DMPLEX` 3278 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3279 3280 Output Parameters: 3281 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3282 . expandedPoints - (optional) An array of recursively expanded cones 3283 - sections - (optional) An array of sections which describe mappings from points to their cone points 3284 3285 Level: advanced 3286 3287 Note: 3288 See `DMPlexGetConeRecursive()` 3289 3290 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3291 `DMPlexGetDepth()`, `IS`, `PetscSection` 3292 @*/ 3293 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3294 { 3295 PetscInt d, depth_; 3296 3297 PetscFunctionBegin; 3298 PetscCall(DMPlexGetDepth(dm, &depth_)); 3299 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3300 if (depth) *depth = 0; 3301 if (expandedPoints) { 3302 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3303 PetscCall(PetscFree(*expandedPoints)); 3304 } 3305 if (sections) { 3306 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3307 PetscCall(PetscFree(*sections)); 3308 } 3309 PetscFunctionReturn(PETSC_SUCCESS); 3310 } 3311 3312 /*@ 3313 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 3314 3315 Not Collective 3316 3317 Input Parameters: 3318 + dm - The `DMPLEX` 3319 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3320 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3321 3322 Level: beginner 3323 3324 Note: 3325 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3326 3327 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3328 @*/ 3329 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3330 { 3331 DM_Plex *mesh = (DM_Plex *)dm->data; 3332 PetscInt dof, off, c; 3333 3334 PetscFunctionBegin; 3335 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3336 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3337 if (dof) PetscAssertPointer(cone, 3); 3338 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3339 if (PetscDefined(USE_DEBUG)) { 3340 PetscInt pStart, pEnd; 3341 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3342 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3343 for (c = 0; c < dof; ++c) { 3344 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); 3345 mesh->cones[off + c] = cone[c]; 3346 } 3347 } else { 3348 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3349 } 3350 PetscFunctionReturn(PETSC_SUCCESS); 3351 } 3352 3353 /*@C 3354 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3355 3356 Not Collective 3357 3358 Input Parameters: 3359 + dm - The `DMPLEX` 3360 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3361 3362 Output Parameter: 3363 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3364 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3365 3366 Level: beginner 3367 3368 Note: 3369 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3370 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3371 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3372 with the identity. 3373 3374 Fortran Notes: 3375 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3376 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3377 3378 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3379 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3380 @*/ 3381 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3382 { 3383 DM_Plex *mesh = (DM_Plex *)dm->data; 3384 PetscInt off; 3385 3386 PetscFunctionBegin; 3387 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3388 if (PetscDefined(USE_DEBUG)) { 3389 PetscInt dof; 3390 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3391 if (dof) PetscAssertPointer(coneOrientation, 3); 3392 } 3393 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3394 3395 *coneOrientation = &mesh->coneOrientations[off]; 3396 PetscFunctionReturn(PETSC_SUCCESS); 3397 } 3398 3399 /*@ 3400 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3401 3402 Not Collective 3403 3404 Input Parameters: 3405 + dm - The `DMPLEX` 3406 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3407 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3408 3409 Level: beginner 3410 3411 Notes: 3412 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3413 3414 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3415 3416 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3417 @*/ 3418 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3419 { 3420 DM_Plex *mesh = (DM_Plex *)dm->data; 3421 PetscInt pStart, pEnd; 3422 PetscInt dof, off, c; 3423 3424 PetscFunctionBegin; 3425 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3426 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3427 if (dof) PetscAssertPointer(coneOrientation, 3); 3428 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3429 if (PetscDefined(USE_DEBUG)) { 3430 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3431 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); 3432 for (c = 0; c < dof; ++c) { 3433 PetscInt cdof, o = coneOrientation[c]; 3434 3435 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3436 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); 3437 mesh->coneOrientations[off + c] = o; 3438 } 3439 } else { 3440 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3441 } 3442 PetscFunctionReturn(PETSC_SUCCESS); 3443 } 3444 3445 /*@ 3446 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3447 3448 Not Collective 3449 3450 Input Parameters: 3451 + dm - The `DMPLEX` 3452 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3453 . conePos - The local index in the cone where the point should be put 3454 - conePoint - The mesh point to insert 3455 3456 Level: beginner 3457 3458 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3459 @*/ 3460 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3461 { 3462 DM_Plex *mesh = (DM_Plex *)dm->data; 3463 PetscInt pStart, pEnd; 3464 PetscInt dof, off; 3465 3466 PetscFunctionBegin; 3467 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3468 if (PetscDefined(USE_DEBUG)) { 3469 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3470 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); 3471 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); 3472 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3473 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); 3474 } 3475 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3476 mesh->cones[off + conePos] = conePoint; 3477 PetscFunctionReturn(PETSC_SUCCESS); 3478 } 3479 3480 /*@ 3481 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3482 3483 Not Collective 3484 3485 Input Parameters: 3486 + dm - The `DMPLEX` 3487 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3488 . conePos - The local index in the cone where the point should be put 3489 - coneOrientation - The point orientation to insert 3490 3491 Level: beginner 3492 3493 Note: 3494 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3495 3496 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3497 @*/ 3498 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3499 { 3500 DM_Plex *mesh = (DM_Plex *)dm->data; 3501 PetscInt pStart, pEnd; 3502 PetscInt dof, off; 3503 3504 PetscFunctionBegin; 3505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3506 if (PetscDefined(USE_DEBUG)) { 3507 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3508 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); 3509 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3510 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); 3511 } 3512 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3513 mesh->coneOrientations[off + conePos] = coneOrientation; 3514 PetscFunctionReturn(PETSC_SUCCESS); 3515 } 3516 3517 /*@C 3518 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3519 3520 Not collective 3521 3522 Input Parameters: 3523 + dm - The DMPlex 3524 - p - The point, which must lie in the chart set with DMPlexSetChart() 3525 3526 Output Parameters: 3527 + cone - An array of points which are on the in-edges for point `p` 3528 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3529 integer giving the prescription for cone traversal. 3530 3531 Level: beginner 3532 3533 Notes: 3534 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3535 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3536 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3537 with the identity. 3538 3539 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3540 3541 Fortran Notes: 3542 `cone` and `ornt` must be declared with 3543 .vb 3544 PetscInt, pointer :: cone(:) 3545 PetscInt, pointer :: ornt(:) 3546 .ve 3547 3548 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3549 @*/ 3550 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3551 { 3552 DM_Plex *mesh = (DM_Plex *)dm->data; 3553 3554 PetscFunctionBegin; 3555 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3556 if (mesh->tr) { 3557 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3558 } else { 3559 PetscInt off; 3560 if (PetscDefined(USE_DEBUG)) { 3561 PetscInt dof; 3562 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3563 if (dof) { 3564 if (cone) PetscAssertPointer(cone, 3); 3565 if (ornt) PetscAssertPointer(ornt, 4); 3566 } 3567 } 3568 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3569 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3570 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3571 } 3572 PetscFunctionReturn(PETSC_SUCCESS); 3573 } 3574 3575 /*@C 3576 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3577 3578 Not Collective 3579 3580 Input Parameters: 3581 + dm - The DMPlex 3582 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3583 . cone - An array of points which are on the in-edges for point p 3584 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3585 integer giving the prescription for cone traversal. 3586 3587 Level: beginner 3588 3589 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3590 @*/ 3591 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3592 { 3593 DM_Plex *mesh = (DM_Plex *)dm->data; 3594 3595 PetscFunctionBegin; 3596 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3597 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3598 PetscFunctionReturn(PETSC_SUCCESS); 3599 } 3600 3601 /*@ 3602 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3603 3604 Not Collective 3605 3606 Input Parameters: 3607 + dm - The `DMPLEX` 3608 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3609 3610 Output Parameter: 3611 . size - The support size for point `p` 3612 3613 Level: beginner 3614 3615 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3616 @*/ 3617 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3618 { 3619 DM_Plex *mesh = (DM_Plex *)dm->data; 3620 3621 PetscFunctionBegin; 3622 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3623 PetscAssertPointer(size, 3); 3624 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3625 PetscFunctionReturn(PETSC_SUCCESS); 3626 } 3627 3628 /*@ 3629 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3630 3631 Not Collective 3632 3633 Input Parameters: 3634 + dm - The `DMPLEX` 3635 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3636 - size - The support size for point `p` 3637 3638 Level: beginner 3639 3640 Note: 3641 This should be called after `DMPlexSetChart()`. 3642 3643 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3644 @*/ 3645 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3646 { 3647 DM_Plex *mesh = (DM_Plex *)dm->data; 3648 3649 PetscFunctionBegin; 3650 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3651 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3652 PetscFunctionReturn(PETSC_SUCCESS); 3653 } 3654 3655 /*@C 3656 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3657 3658 Not Collective 3659 3660 Input Parameters: 3661 + dm - The `DMPLEX` 3662 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3663 3664 Output Parameter: 3665 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3666 3667 Level: beginner 3668 3669 Fortran Notes: 3670 `support` must be declared with 3671 .vb 3672 PetscInt, pointer :: support(:) 3673 .ve 3674 3675 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3676 `DMPlexRestoreSupport()` is not needed/available in C. 3677 3678 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3679 @*/ 3680 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3681 { 3682 DM_Plex *mesh = (DM_Plex *)dm->data; 3683 PetscInt off; 3684 3685 PetscFunctionBegin; 3686 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3687 PetscAssertPointer(support, 3); 3688 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3689 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3690 PetscFunctionReturn(PETSC_SUCCESS); 3691 } 3692 3693 /*@ 3694 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3695 3696 Not Collective 3697 3698 Input Parameters: 3699 + dm - The `DMPLEX` 3700 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3701 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3702 3703 Level: beginner 3704 3705 Note: 3706 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3707 3708 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3709 @*/ 3710 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3711 { 3712 DM_Plex *mesh = (DM_Plex *)dm->data; 3713 PetscInt pStart, pEnd; 3714 PetscInt dof, off, c; 3715 3716 PetscFunctionBegin; 3717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3718 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3719 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3720 if (dof) PetscAssertPointer(support, 3); 3721 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3722 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); 3723 for (c = 0; c < dof; ++c) { 3724 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); 3725 mesh->supports[off + c] = support[c]; 3726 } 3727 PetscFunctionReturn(PETSC_SUCCESS); 3728 } 3729 3730 /*@ 3731 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3732 3733 Not Collective 3734 3735 Input Parameters: 3736 + dm - The `DMPLEX` 3737 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3738 . supportPos - The local index in the cone where the point should be put 3739 - supportPoint - The mesh point to insert 3740 3741 Level: beginner 3742 3743 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3744 @*/ 3745 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3746 { 3747 DM_Plex *mesh = (DM_Plex *)dm->data; 3748 PetscInt pStart, pEnd; 3749 PetscInt dof, off; 3750 3751 PetscFunctionBegin; 3752 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3753 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3754 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3755 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3756 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); 3757 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); 3758 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); 3759 mesh->supports[off + supportPos] = supportPoint; 3760 PetscFunctionReturn(PETSC_SUCCESS); 3761 } 3762 3763 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3764 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3765 { 3766 switch (ct) { 3767 case DM_POLYTOPE_SEGMENT: 3768 if (o == -1) return -2; 3769 break; 3770 case DM_POLYTOPE_TRIANGLE: 3771 if (o == -3) return -1; 3772 if (o == -2) return -3; 3773 if (o == -1) return -2; 3774 break; 3775 case DM_POLYTOPE_QUADRILATERAL: 3776 if (o == -4) return -2; 3777 if (o == -3) return -1; 3778 if (o == -2) return -4; 3779 if (o == -1) return -3; 3780 break; 3781 default: 3782 return o; 3783 } 3784 return o; 3785 } 3786 3787 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3788 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3789 { 3790 switch (ct) { 3791 case DM_POLYTOPE_SEGMENT: 3792 if ((o == -2) || (o == 1)) return -1; 3793 if (o == -1) return 0; 3794 break; 3795 case DM_POLYTOPE_TRIANGLE: 3796 if (o == -3) return -2; 3797 if (o == -2) return -1; 3798 if (o == -1) return -3; 3799 break; 3800 case DM_POLYTOPE_QUADRILATERAL: 3801 if (o == -4) return -2; 3802 if (o == -3) return -1; 3803 if (o == -2) return -4; 3804 if (o == -1) return -3; 3805 break; 3806 default: 3807 return o; 3808 } 3809 return o; 3810 } 3811 3812 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3813 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3814 { 3815 PetscInt pStart, pEnd, p; 3816 3817 PetscFunctionBegin; 3818 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3819 for (p = pStart; p < pEnd; ++p) { 3820 const PetscInt *cone, *ornt; 3821 PetscInt coneSize, c; 3822 3823 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3824 PetscCall(DMPlexGetCone(dm, p, &cone)); 3825 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3826 for (c = 0; c < coneSize; ++c) { 3827 DMPolytopeType ct; 3828 const PetscInt o = ornt[c]; 3829 3830 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3831 switch (ct) { 3832 case DM_POLYTOPE_SEGMENT: 3833 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3834 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3835 break; 3836 case DM_POLYTOPE_TRIANGLE: 3837 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3838 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3839 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3840 break; 3841 case DM_POLYTOPE_QUADRILATERAL: 3842 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3843 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3844 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3845 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3846 break; 3847 default: 3848 break; 3849 } 3850 } 3851 } 3852 PetscFunctionReturn(PETSC_SUCCESS); 3853 } 3854 3855 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3856 { 3857 DM_Plex *mesh = (DM_Plex *)dm->data; 3858 3859 PetscFunctionBeginHot; 3860 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3861 if (useCone) { 3862 PetscCall(DMPlexGetConeSize(dm, p, size)); 3863 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3864 } else { 3865 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3866 PetscCall(DMPlexGetSupport(dm, p, arr)); 3867 } 3868 } else { 3869 if (useCone) { 3870 const PetscSection s = mesh->coneSection; 3871 const PetscInt ps = p - s->pStart; 3872 const PetscInt off = s->atlasOff[ps]; 3873 3874 *size = s->atlasDof[ps]; 3875 *arr = mesh->cones + off; 3876 *ornt = mesh->coneOrientations + off; 3877 } else { 3878 const PetscSection s = mesh->supportSection; 3879 const PetscInt ps = p - s->pStart; 3880 const PetscInt off = s->atlasOff[ps]; 3881 3882 *size = s->atlasDof[ps]; 3883 *arr = mesh->supports + off; 3884 } 3885 } 3886 PetscFunctionReturn(PETSC_SUCCESS); 3887 } 3888 3889 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3890 { 3891 DM_Plex *mesh = (DM_Plex *)dm->data; 3892 3893 PetscFunctionBeginHot; 3894 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3895 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3896 } 3897 PetscFunctionReturn(PETSC_SUCCESS); 3898 } 3899 3900 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3901 { 3902 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3903 PetscInt *closure; 3904 const PetscInt *tmp = NULL, *tmpO = NULL; 3905 PetscInt off = 0, tmpSize, t; 3906 3907 PetscFunctionBeginHot; 3908 if (ornt) { 3909 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3910 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; 3911 } 3912 if (*points) { 3913 closure = *points; 3914 } else { 3915 PetscInt maxConeSize, maxSupportSize; 3916 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3917 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3918 } 3919 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3920 if (ct == DM_POLYTOPE_UNKNOWN) { 3921 closure[off++] = p; 3922 closure[off++] = 0; 3923 for (t = 0; t < tmpSize; ++t) { 3924 closure[off++] = tmp[t]; 3925 closure[off++] = tmpO ? tmpO[t] : 0; 3926 } 3927 } else { 3928 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3929 3930 /* We assume that cells with a valid type have faces with a valid type */ 3931 closure[off++] = p; 3932 closure[off++] = ornt; 3933 for (t = 0; t < tmpSize; ++t) { 3934 DMPolytopeType ft; 3935 3936 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3937 closure[off++] = tmp[arr[t]]; 3938 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3939 } 3940 } 3941 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3942 if (numPoints) *numPoints = tmpSize + 1; 3943 if (points) *points = closure; 3944 PetscFunctionReturn(PETSC_SUCCESS); 3945 } 3946 3947 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3948 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3949 { 3950 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3951 const PetscInt *cone, *ornt; 3952 PetscInt *pts, *closure = NULL; 3953 DMPolytopeType ft; 3954 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3955 PetscInt dim, coneSize, c, d, clSize, cl; 3956 3957 PetscFunctionBeginHot; 3958 PetscCall(DMGetDimension(dm, &dim)); 3959 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3960 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3961 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3962 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3963 maxSize = PetscMax(coneSeries, supportSeries); 3964 if (*points) { 3965 pts = *points; 3966 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3967 c = 0; 3968 pts[c++] = point; 3969 pts[c++] = o; 3970 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3971 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3972 for (cl = 0; cl < clSize * 2; cl += 2) { 3973 pts[c++] = closure[cl]; 3974 pts[c++] = closure[cl + 1]; 3975 } 3976 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3977 for (cl = 0; cl < clSize * 2; cl += 2) { 3978 pts[c++] = closure[cl]; 3979 pts[c++] = closure[cl + 1]; 3980 } 3981 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3982 for (d = 2; d < coneSize; ++d) { 3983 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3984 pts[c++] = cone[arr[d * 2 + 0]]; 3985 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3986 } 3987 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3988 if (dim >= 3) { 3989 for (d = 2; d < coneSize; ++d) { 3990 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3991 const PetscInt *fcone, *fornt; 3992 PetscInt fconeSize, fc, i; 3993 3994 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3995 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3996 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3997 for (fc = 0; fc < fconeSize; ++fc) { 3998 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3999 const PetscInt co = farr[fc * 2 + 1]; 4000 4001 for (i = 0; i < c; i += 2) 4002 if (pts[i] == cp) break; 4003 if (i == c) { 4004 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4005 pts[c++] = cp; 4006 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4007 } 4008 } 4009 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4010 } 4011 } 4012 *numPoints = c / 2; 4013 *points = pts; 4014 PetscFunctionReturn(PETSC_SUCCESS); 4015 } 4016 4017 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4018 { 4019 DMPolytopeType ct; 4020 PetscInt *closure, *fifo; 4021 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4022 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4023 PetscInt depth, maxSize; 4024 4025 PetscFunctionBeginHot; 4026 PetscCall(DMPlexGetDepth(dm, &depth)); 4027 if (depth == 1) { 4028 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4029 PetscFunctionReturn(PETSC_SUCCESS); 4030 } 4031 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4032 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; 4033 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4034 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4035 PetscFunctionReturn(PETSC_SUCCESS); 4036 } 4037 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4038 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4039 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4040 maxSize = PetscMax(coneSeries, supportSeries); 4041 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4042 if (*points) { 4043 closure = *points; 4044 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4045 closure[closureSize++] = p; 4046 closure[closureSize++] = ornt; 4047 fifo[fifoSize++] = p; 4048 fifo[fifoSize++] = ornt; 4049 fifo[fifoSize++] = ct; 4050 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4051 while (fifoSize - fifoStart) { 4052 const PetscInt q = fifo[fifoStart++]; 4053 const PetscInt o = fifo[fifoStart++]; 4054 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4055 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4056 const PetscInt *tmp, *tmpO = NULL; 4057 PetscInt tmpSize, t; 4058 4059 if (PetscDefined(USE_DEBUG)) { 4060 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4061 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); 4062 } 4063 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4064 for (t = 0; t < tmpSize; ++t) { 4065 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4066 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4067 const PetscInt cp = tmp[ip]; 4068 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4069 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4070 PetscInt c; 4071 4072 /* Check for duplicate */ 4073 for (c = 0; c < closureSize; c += 2) { 4074 if (closure[c] == cp) break; 4075 } 4076 if (c == closureSize) { 4077 closure[closureSize++] = cp; 4078 closure[closureSize++] = co; 4079 fifo[fifoSize++] = cp; 4080 fifo[fifoSize++] = co; 4081 fifo[fifoSize++] = ct; 4082 } 4083 } 4084 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4085 } 4086 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4087 if (numPoints) *numPoints = closureSize / 2; 4088 if (points) *points = closure; 4089 PetscFunctionReturn(PETSC_SUCCESS); 4090 } 4091 4092 /*@C 4093 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4094 4095 Not Collective 4096 4097 Input Parameters: 4098 + dm - The `DMPLEX` 4099 . p - The mesh point 4100 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4101 4102 Input/Output Parameter: 4103 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4104 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4105 otherwise the provided array is used to hold the values 4106 4107 Output Parameter: 4108 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4109 4110 Level: beginner 4111 4112 Note: 4113 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4114 4115 Fortran Notes: 4116 `points` must be declared with 4117 .vb 4118 PetscInt, pointer :: points(:) 4119 .ve 4120 and is always allocated by the function. 4121 4122 The `numPoints` argument is not present in the Fortran binding. 4123 4124 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4125 @*/ 4126 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4127 { 4128 PetscFunctionBeginHot; 4129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4130 if (numPoints) PetscAssertPointer(numPoints, 4); 4131 if (points) PetscAssertPointer(points, 5); 4132 if (PetscDefined(USE_DEBUG)) { 4133 PetscInt pStart, pEnd; 4134 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4135 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); 4136 } 4137 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4138 PetscFunctionReturn(PETSC_SUCCESS); 4139 } 4140 4141 /*@C 4142 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4143 4144 Not Collective 4145 4146 Input Parameters: 4147 + dm - The `DMPLEX` 4148 . p - The mesh point 4149 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4150 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4151 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4152 4153 Level: beginner 4154 4155 Note: 4156 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4157 4158 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4159 @*/ 4160 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4161 { 4162 PetscFunctionBeginHot; 4163 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4164 if (numPoints) *numPoints = 0; 4165 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4166 PetscFunctionReturn(PETSC_SUCCESS); 4167 } 4168 4169 /*@ 4170 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4171 4172 Not Collective 4173 4174 Input Parameter: 4175 . dm - The `DMPLEX` 4176 4177 Output Parameters: 4178 + maxConeSize - The maximum number of in-edges 4179 - maxSupportSize - The maximum number of out-edges 4180 4181 Level: beginner 4182 4183 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4184 @*/ 4185 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4186 { 4187 DM_Plex *mesh = (DM_Plex *)dm->data; 4188 4189 PetscFunctionBegin; 4190 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4191 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4192 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4193 PetscFunctionReturn(PETSC_SUCCESS); 4194 } 4195 4196 PetscErrorCode DMSetUp_Plex(DM dm) 4197 { 4198 DM_Plex *mesh = (DM_Plex *)dm->data; 4199 PetscInt size, maxSupportSize; 4200 4201 PetscFunctionBegin; 4202 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4203 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4204 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4205 PetscCall(PetscMalloc1(size, &mesh->cones)); 4206 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4207 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4208 if (maxSupportSize) { 4209 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4210 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4211 PetscCall(PetscMalloc1(size, &mesh->supports)); 4212 } 4213 PetscFunctionReturn(PETSC_SUCCESS); 4214 } 4215 4216 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4217 { 4218 PetscFunctionBegin; 4219 if (subdm) PetscCall(DMClone(dm, subdm)); 4220 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4221 if (subdm) (*subdm)->useNatural = dm->useNatural; 4222 if (dm->useNatural && dm->sfMigration) { 4223 PetscSF sfNatural; 4224 4225 (*subdm)->sfMigration = dm->sfMigration; 4226 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4227 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4228 (*subdm)->sfNatural = sfNatural; 4229 } 4230 PetscFunctionReturn(PETSC_SUCCESS); 4231 } 4232 4233 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4234 { 4235 PetscInt i = 0; 4236 4237 PetscFunctionBegin; 4238 PetscCall(DMClone(dms[0], superdm)); 4239 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4240 (*superdm)->useNatural = PETSC_FALSE; 4241 for (i = 0; i < len; i++) { 4242 if (dms[i]->useNatural && dms[i]->sfMigration) { 4243 PetscSF sfNatural; 4244 4245 (*superdm)->sfMigration = dms[i]->sfMigration; 4246 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4247 (*superdm)->useNatural = PETSC_TRUE; 4248 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4249 (*superdm)->sfNatural = sfNatural; 4250 break; 4251 } 4252 } 4253 PetscFunctionReturn(PETSC_SUCCESS); 4254 } 4255 4256 /*@ 4257 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4258 4259 Not Collective 4260 4261 Input Parameter: 4262 . dm - The `DMPLEX` 4263 4264 Level: beginner 4265 4266 Note: 4267 This should be called after all calls to `DMPlexSetCone()` 4268 4269 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4270 @*/ 4271 PetscErrorCode DMPlexSymmetrize(DM dm) 4272 { 4273 DM_Plex *mesh = (DM_Plex *)dm->data; 4274 PetscInt *offsets; 4275 PetscInt supportSize; 4276 PetscInt pStart, pEnd, p; 4277 4278 PetscFunctionBegin; 4279 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4280 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4281 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4282 /* Calculate support sizes */ 4283 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4284 for (p = pStart; p < pEnd; ++p) { 4285 PetscInt dof, off, c; 4286 4287 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4288 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4289 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4290 } 4291 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4292 /* Calculate supports */ 4293 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4294 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4295 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4296 for (p = pStart; p < pEnd; ++p) { 4297 PetscInt dof, off, c; 4298 4299 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4300 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4301 for (c = off; c < off + dof; ++c) { 4302 const PetscInt q = mesh->cones[c]; 4303 PetscInt offS; 4304 4305 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4306 4307 mesh->supports[offS + offsets[q]] = p; 4308 ++offsets[q]; 4309 } 4310 } 4311 PetscCall(PetscFree(offsets)); 4312 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4313 PetscFunctionReturn(PETSC_SUCCESS); 4314 } 4315 4316 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4317 { 4318 IS stratumIS; 4319 4320 PetscFunctionBegin; 4321 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4322 if (PetscDefined(USE_DEBUG)) { 4323 PetscInt qStart, qEnd, numLevels, level; 4324 PetscBool overlap = PETSC_FALSE; 4325 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4326 for (level = 0; level < numLevels; level++) { 4327 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4328 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4329 overlap = PETSC_TRUE; 4330 break; 4331 } 4332 } 4333 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); 4334 } 4335 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4336 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4337 PetscCall(ISDestroy(&stratumIS)); 4338 PetscFunctionReturn(PETSC_SUCCESS); 4339 } 4340 4341 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4342 { 4343 PetscInt *pMin, *pMax; 4344 PetscInt pStart, pEnd; 4345 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4346 4347 PetscFunctionBegin; 4348 { 4349 DMLabel label2; 4350 4351 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4352 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4353 } 4354 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4355 for (PetscInt p = pStart; p < pEnd; ++p) { 4356 DMPolytopeType ct; 4357 4358 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4359 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4360 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4361 } 4362 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4363 for (PetscInt d = dmin; d <= dmax; ++d) { 4364 pMin[d] = PETSC_MAX_INT; 4365 pMax[d] = PETSC_MIN_INT; 4366 } 4367 for (PetscInt p = pStart; p < pEnd; ++p) { 4368 DMPolytopeType ct; 4369 PetscInt d; 4370 4371 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4372 d = DMPolytopeTypeGetDim(ct); 4373 pMin[d] = PetscMin(p, pMin[d]); 4374 pMax[d] = PetscMax(p, pMax[d]); 4375 } 4376 for (PetscInt d = dmin; d <= dmax; ++d) { 4377 if (pMin[d] > pMax[d]) continue; 4378 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4379 } 4380 PetscCall(PetscFree2(pMin, pMax)); 4381 PetscFunctionReturn(PETSC_SUCCESS); 4382 } 4383 4384 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4385 { 4386 PetscInt pStart, pEnd; 4387 PetscInt numRoots = 0, numLeaves = 0; 4388 4389 PetscFunctionBegin; 4390 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4391 { 4392 /* Initialize roots and count leaves */ 4393 PetscInt sMin = PETSC_MAX_INT; 4394 PetscInt sMax = PETSC_MIN_INT; 4395 PetscInt coneSize, supportSize; 4396 4397 for (PetscInt p = pStart; p < pEnd; ++p) { 4398 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4399 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4400 if (!coneSize && supportSize) { 4401 sMin = PetscMin(p, sMin); 4402 sMax = PetscMax(p, sMax); 4403 ++numRoots; 4404 } else if (!supportSize && coneSize) { 4405 ++numLeaves; 4406 } else if (!supportSize && !coneSize) { 4407 /* Isolated points */ 4408 sMin = PetscMin(p, sMin); 4409 sMax = PetscMax(p, sMax); 4410 } 4411 } 4412 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4413 } 4414 4415 if (numRoots + numLeaves == (pEnd - pStart)) { 4416 PetscInt sMin = PETSC_MAX_INT; 4417 PetscInt sMax = PETSC_MIN_INT; 4418 PetscInt coneSize, supportSize; 4419 4420 for (PetscInt p = pStart; p < pEnd; ++p) { 4421 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4422 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4423 if (!supportSize && coneSize) { 4424 sMin = PetscMin(p, sMin); 4425 sMax = PetscMax(p, sMax); 4426 } 4427 } 4428 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4429 } else { 4430 PetscInt level = 0; 4431 PetscInt qStart, qEnd; 4432 4433 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4434 while (qEnd > qStart) { 4435 PetscInt sMin = PETSC_MAX_INT; 4436 PetscInt sMax = PETSC_MIN_INT; 4437 4438 for (PetscInt q = qStart; q < qEnd; ++q) { 4439 const PetscInt *support; 4440 PetscInt supportSize; 4441 4442 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4443 PetscCall(DMPlexGetSupport(dm, q, &support)); 4444 for (PetscInt s = 0; s < supportSize; ++s) { 4445 sMin = PetscMin(support[s], sMin); 4446 sMax = PetscMax(support[s], sMax); 4447 } 4448 } 4449 PetscCall(DMLabelGetNumValues(label, &level)); 4450 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4451 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4452 } 4453 } 4454 PetscFunctionReturn(PETSC_SUCCESS); 4455 } 4456 4457 /*@ 4458 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4459 4460 Collective 4461 4462 Input Parameter: 4463 . dm - The `DMPLEX` 4464 4465 Level: beginner 4466 4467 Notes: 4468 The strata group all points of the same grade, and this function calculates the strata. This 4469 grade can be seen as the height (or depth) of the point in the DAG. 4470 4471 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4472 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4473 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4474 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4475 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4476 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4477 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4478 4479 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4480 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4481 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 4482 to interpolate only that one (e0), so that 4483 .vb 4484 cone(c0) = {e0, v2} 4485 cone(e0) = {v0, v1} 4486 .ve 4487 If `DMPlexStratify()` is run on this mesh, it will give depths 4488 .vb 4489 depth 0 = {v0, v1, v2} 4490 depth 1 = {e0, c0} 4491 .ve 4492 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4493 4494 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4495 4496 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4497 @*/ 4498 PetscErrorCode DMPlexStratify(DM dm) 4499 { 4500 DM_Plex *mesh = (DM_Plex *)dm->data; 4501 DMLabel label; 4502 PetscBool flg = PETSC_FALSE; 4503 4504 PetscFunctionBegin; 4505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4506 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4507 4508 // Create depth label 4509 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4510 PetscCall(DMCreateLabel(dm, "depth")); 4511 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4512 4513 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4514 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4515 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4516 4517 { /* just in case there is an empty process */ 4518 PetscInt numValues, maxValues = 0, v; 4519 4520 PetscCall(DMLabelGetNumValues(label, &numValues)); 4521 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4522 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4523 } 4524 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4525 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4526 PetscFunctionReturn(PETSC_SUCCESS); 4527 } 4528 4529 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4530 { 4531 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4532 PetscInt dim, depth, pheight, coneSize; 4533 4534 PetscFunctionBeginHot; 4535 PetscCall(DMGetDimension(dm, &dim)); 4536 PetscCall(DMPlexGetDepth(dm, &depth)); 4537 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4538 pheight = depth - pdepth; 4539 if (depth <= 1) { 4540 switch (pdepth) { 4541 case 0: 4542 ct = DM_POLYTOPE_POINT; 4543 break; 4544 case 1: 4545 switch (coneSize) { 4546 case 2: 4547 ct = DM_POLYTOPE_SEGMENT; 4548 break; 4549 case 3: 4550 ct = DM_POLYTOPE_TRIANGLE; 4551 break; 4552 case 4: 4553 switch (dim) { 4554 case 2: 4555 ct = DM_POLYTOPE_QUADRILATERAL; 4556 break; 4557 case 3: 4558 ct = DM_POLYTOPE_TETRAHEDRON; 4559 break; 4560 default: 4561 break; 4562 } 4563 break; 4564 case 5: 4565 ct = DM_POLYTOPE_PYRAMID; 4566 break; 4567 case 6: 4568 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4569 break; 4570 case 8: 4571 ct = DM_POLYTOPE_HEXAHEDRON; 4572 break; 4573 default: 4574 break; 4575 } 4576 } 4577 } else { 4578 if (pdepth == 0) { 4579 ct = DM_POLYTOPE_POINT; 4580 } else if (pheight == 0) { 4581 switch (dim) { 4582 case 1: 4583 switch (coneSize) { 4584 case 2: 4585 ct = DM_POLYTOPE_SEGMENT; 4586 break; 4587 default: 4588 break; 4589 } 4590 break; 4591 case 2: 4592 switch (coneSize) { 4593 case 3: 4594 ct = DM_POLYTOPE_TRIANGLE; 4595 break; 4596 case 4: 4597 ct = DM_POLYTOPE_QUADRILATERAL; 4598 break; 4599 default: 4600 break; 4601 } 4602 break; 4603 case 3: 4604 switch (coneSize) { 4605 case 4: 4606 ct = DM_POLYTOPE_TETRAHEDRON; 4607 break; 4608 case 5: { 4609 const PetscInt *cone; 4610 PetscInt faceConeSize; 4611 4612 PetscCall(DMPlexGetCone(dm, p, &cone)); 4613 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4614 switch (faceConeSize) { 4615 case 3: 4616 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4617 break; 4618 case 4: 4619 ct = DM_POLYTOPE_PYRAMID; 4620 break; 4621 } 4622 } break; 4623 case 6: 4624 ct = DM_POLYTOPE_HEXAHEDRON; 4625 break; 4626 default: 4627 break; 4628 } 4629 break; 4630 default: 4631 break; 4632 } 4633 } else if (pheight > 0) { 4634 switch (coneSize) { 4635 case 2: 4636 ct = DM_POLYTOPE_SEGMENT; 4637 break; 4638 case 3: 4639 ct = DM_POLYTOPE_TRIANGLE; 4640 break; 4641 case 4: 4642 ct = DM_POLYTOPE_QUADRILATERAL; 4643 break; 4644 default: 4645 break; 4646 } 4647 } 4648 } 4649 *pt = ct; 4650 PetscFunctionReturn(PETSC_SUCCESS); 4651 } 4652 4653 /*@ 4654 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4655 4656 Collective 4657 4658 Input Parameter: 4659 . dm - The `DMPLEX` 4660 4661 Level: developer 4662 4663 Note: 4664 This function is normally called automatically when a cell type is requested. It creates an 4665 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4666 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4667 4668 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4669 4670 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4671 @*/ 4672 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4673 { 4674 DM_Plex *mesh; 4675 DMLabel ctLabel; 4676 PetscInt pStart, pEnd, p; 4677 4678 PetscFunctionBegin; 4679 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4680 mesh = (DM_Plex *)dm->data; 4681 PetscCall(DMCreateLabel(dm, "celltype")); 4682 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4683 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4684 PetscCall(PetscFree(mesh->cellTypes)); 4685 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4686 for (p = pStart; p < pEnd; ++p) { 4687 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4688 PetscInt pdepth; 4689 4690 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4691 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4692 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]); 4693 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4694 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4695 } 4696 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4697 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4698 PetscFunctionReturn(PETSC_SUCCESS); 4699 } 4700 4701 /*@C 4702 DMPlexGetJoin - Get an array for the join of the set of points 4703 4704 Not Collective 4705 4706 Input Parameters: 4707 + dm - The `DMPLEX` object 4708 . numPoints - The number of input points for the join 4709 - points - The input points 4710 4711 Output Parameters: 4712 + numCoveredPoints - The number of points in the join 4713 - coveredPoints - The points in the join 4714 4715 Level: intermediate 4716 4717 Note: 4718 Currently, this is restricted to a single level join 4719 4720 Fortran Notes: 4721 `converedPoints` must be declared with 4722 .vb 4723 PetscInt, pointer :: coveredPints(:) 4724 .ve 4725 4726 The `numCoveredPoints` argument is not present in the Fortran binding. 4727 4728 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4729 @*/ 4730 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4731 { 4732 DM_Plex *mesh = (DM_Plex *)dm->data; 4733 PetscInt *join[2]; 4734 PetscInt joinSize, i = 0; 4735 PetscInt dof, off, p, c, m; 4736 PetscInt maxSupportSize; 4737 4738 PetscFunctionBegin; 4739 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4740 PetscAssertPointer(points, 3); 4741 PetscAssertPointer(numCoveredPoints, 4); 4742 PetscAssertPointer(coveredPoints, 5); 4743 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4744 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4745 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4746 /* Copy in support of first point */ 4747 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4748 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4749 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4750 /* Check each successive support */ 4751 for (p = 1; p < numPoints; ++p) { 4752 PetscInt newJoinSize = 0; 4753 4754 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4755 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4756 for (c = 0; c < dof; ++c) { 4757 const PetscInt point = mesh->supports[off + c]; 4758 4759 for (m = 0; m < joinSize; ++m) { 4760 if (point == join[i][m]) { 4761 join[1 - i][newJoinSize++] = point; 4762 break; 4763 } 4764 } 4765 } 4766 joinSize = newJoinSize; 4767 i = 1 - i; 4768 } 4769 *numCoveredPoints = joinSize; 4770 *coveredPoints = join[i]; 4771 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4772 PetscFunctionReturn(PETSC_SUCCESS); 4773 } 4774 4775 /*@C 4776 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4777 4778 Not Collective 4779 4780 Input Parameters: 4781 + dm - The `DMPLEX` object 4782 . numPoints - The number of input points for the join 4783 - points - The input points 4784 4785 Output Parameters: 4786 + numCoveredPoints - The number of points in the join 4787 - coveredPoints - The points in the join 4788 4789 Level: intermediate 4790 4791 Fortran Notes: 4792 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4793 4794 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4795 @*/ 4796 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4797 { 4798 PetscFunctionBegin; 4799 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4800 if (points) PetscAssertPointer(points, 3); 4801 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4802 PetscAssertPointer(coveredPoints, 5); 4803 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4804 if (numCoveredPoints) *numCoveredPoints = 0; 4805 PetscFunctionReturn(PETSC_SUCCESS); 4806 } 4807 4808 /*@C 4809 DMPlexGetFullJoin - Get an array for the join of the set of points 4810 4811 Not Collective 4812 4813 Input Parameters: 4814 + dm - The `DMPLEX` object 4815 . numPoints - The number of input points for the join 4816 - points - The input points, its length is `numPoints` 4817 4818 Output Parameters: 4819 + numCoveredPoints - The number of points in the join 4820 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4821 4822 Level: intermediate 4823 4824 Fortran Notes: 4825 `points` and `converedPoints` must be declared with 4826 .vb 4827 PetscInt, pointer :: points(:) 4828 PetscInt, pointer :: coveredPints(:) 4829 .ve 4830 4831 The `numCoveredPoints` argument is not present in the Fortran binding. 4832 4833 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4834 @*/ 4835 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4836 { 4837 PetscInt *offsets, **closures; 4838 PetscInt *join[2]; 4839 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4840 PetscInt p, d, c, m, ms; 4841 4842 PetscFunctionBegin; 4843 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4844 PetscAssertPointer(points, 3); 4845 PetscAssertPointer(numCoveredPoints, 4); 4846 PetscAssertPointer(coveredPoints, 5); 4847 4848 PetscCall(DMPlexGetDepth(dm, &depth)); 4849 PetscCall(PetscCalloc1(numPoints, &closures)); 4850 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4851 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4852 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4853 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4854 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4855 4856 for (p = 0; p < numPoints; ++p) { 4857 PetscInt closureSize; 4858 4859 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4860 4861 offsets[p * (depth + 2) + 0] = 0; 4862 for (d = 0; d < depth + 1; ++d) { 4863 PetscInt pStart, pEnd, i; 4864 4865 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4866 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4867 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4868 offsets[p * (depth + 2) + d + 1] = i; 4869 break; 4870 } 4871 } 4872 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4873 } 4874 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); 4875 } 4876 for (d = 0; d < depth + 1; ++d) { 4877 PetscInt dof; 4878 4879 /* Copy in support of first point */ 4880 dof = offsets[d + 1] - offsets[d]; 4881 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4882 /* Check each successive cone */ 4883 for (p = 1; p < numPoints && joinSize; ++p) { 4884 PetscInt newJoinSize = 0; 4885 4886 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4887 for (c = 0; c < dof; ++c) { 4888 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4889 4890 for (m = 0; m < joinSize; ++m) { 4891 if (point == join[i][m]) { 4892 join[1 - i][newJoinSize++] = point; 4893 break; 4894 } 4895 } 4896 } 4897 joinSize = newJoinSize; 4898 i = 1 - i; 4899 } 4900 if (joinSize) break; 4901 } 4902 *numCoveredPoints = joinSize; 4903 *coveredPoints = join[i]; 4904 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4905 PetscCall(PetscFree(closures)); 4906 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4907 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4908 PetscFunctionReturn(PETSC_SUCCESS); 4909 } 4910 4911 /*@C 4912 DMPlexGetMeet - Get an array for the meet of the set of points 4913 4914 Not Collective 4915 4916 Input Parameters: 4917 + dm - The `DMPLEX` object 4918 . numPoints - The number of input points for the meet 4919 - points - The input points, of length `numPoints` 4920 4921 Output Parameters: 4922 + numCoveringPoints - The number of points in the meet 4923 - coveringPoints - The points in the meet, of length `numCoveringPoints` 4924 4925 Level: intermediate 4926 4927 Note: 4928 Currently, this is restricted to a single level meet 4929 4930 Fortran Notes: 4931 `coveringPoints` must be declared with 4932 .vb 4933 PetscInt, pointer :: coveringPoints(:) 4934 .ve 4935 4936 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4937 4938 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4939 @*/ 4940 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 4941 { 4942 DM_Plex *mesh = (DM_Plex *)dm->data; 4943 PetscInt *meet[2]; 4944 PetscInt meetSize, i = 0; 4945 PetscInt dof, off, p, c, m; 4946 PetscInt maxConeSize; 4947 4948 PetscFunctionBegin; 4949 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4950 PetscAssertPointer(points, 3); 4951 PetscAssertPointer(numCoveringPoints, 4); 4952 PetscAssertPointer(coveringPoints, 5); 4953 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4954 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4955 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4956 /* Copy in cone of first point */ 4957 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4958 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4959 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4960 /* Check each successive cone */ 4961 for (p = 1; p < numPoints; ++p) { 4962 PetscInt newMeetSize = 0; 4963 4964 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4965 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4966 for (c = 0; c < dof; ++c) { 4967 const PetscInt point = mesh->cones[off + c]; 4968 4969 for (m = 0; m < meetSize; ++m) { 4970 if (point == meet[i][m]) { 4971 meet[1 - i][newMeetSize++] = point; 4972 break; 4973 } 4974 } 4975 } 4976 meetSize = newMeetSize; 4977 i = 1 - i; 4978 } 4979 *numCoveringPoints = meetSize; 4980 *coveringPoints = meet[i]; 4981 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4982 PetscFunctionReturn(PETSC_SUCCESS); 4983 } 4984 4985 /*@C 4986 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 4987 4988 Not Collective 4989 4990 Input Parameters: 4991 + dm - The `DMPLEX` object 4992 . numPoints - The number of input points for the meet 4993 - points - The input points 4994 4995 Output Parameters: 4996 + numCoveredPoints - The number of points in the meet 4997 - coveredPoints - The points in the meet 4998 4999 Level: intermediate 5000 5001 Fortran Notes: 5002 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5003 5004 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5005 @*/ 5006 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5007 { 5008 PetscFunctionBegin; 5009 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5010 if (points) PetscAssertPointer(points, 3); 5011 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5012 PetscAssertPointer(coveredPoints, 5); 5013 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5014 if (numCoveredPoints) *numCoveredPoints = 0; 5015 PetscFunctionReturn(PETSC_SUCCESS); 5016 } 5017 5018 /*@C 5019 DMPlexGetFullMeet - Get an array for the meet of the set of points 5020 5021 Not Collective 5022 5023 Input Parameters: 5024 + dm - The `DMPLEX` object 5025 . numPoints - The number of input points for the meet 5026 - points - The input points, of length `numPoints` 5027 5028 Output Parameters: 5029 + numCoveredPoints - The number of points in the meet 5030 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5031 5032 Level: intermediate 5033 5034 Fortran Notes: 5035 `points` and `coveredPoints` must be declared with 5036 .vb 5037 PetscInt, pointer :: points(:) 5038 PetscInt, pointer :: coveredPoints(:) 5039 .ve 5040 5041 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5042 5043 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5044 @*/ 5045 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5046 { 5047 PetscInt *offsets, **closures; 5048 PetscInt *meet[2]; 5049 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5050 PetscInt p, h, c, m, mc; 5051 5052 PetscFunctionBegin; 5053 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5054 PetscAssertPointer(points, 3); 5055 PetscAssertPointer(numCoveredPoints, 4); 5056 PetscAssertPointer(coveredPoints, 5); 5057 5058 PetscCall(DMPlexGetDepth(dm, &height)); 5059 PetscCall(PetscMalloc1(numPoints, &closures)); 5060 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5061 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5062 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5063 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5064 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5065 5066 for (p = 0; p < numPoints; ++p) { 5067 PetscInt closureSize; 5068 5069 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5070 5071 offsets[p * (height + 2) + 0] = 0; 5072 for (h = 0; h < height + 1; ++h) { 5073 PetscInt pStart, pEnd, i; 5074 5075 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5076 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5077 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5078 offsets[p * (height + 2) + h + 1] = i; 5079 break; 5080 } 5081 } 5082 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5083 } 5084 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); 5085 } 5086 for (h = 0; h < height + 1; ++h) { 5087 PetscInt dof; 5088 5089 /* Copy in cone of first point */ 5090 dof = offsets[h + 1] - offsets[h]; 5091 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5092 /* Check each successive cone */ 5093 for (p = 1; p < numPoints && meetSize; ++p) { 5094 PetscInt newMeetSize = 0; 5095 5096 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5097 for (c = 0; c < dof; ++c) { 5098 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5099 5100 for (m = 0; m < meetSize; ++m) { 5101 if (point == meet[i][m]) { 5102 meet[1 - i][newMeetSize++] = point; 5103 break; 5104 } 5105 } 5106 } 5107 meetSize = newMeetSize; 5108 i = 1 - i; 5109 } 5110 if (meetSize) break; 5111 } 5112 *numCoveredPoints = meetSize; 5113 *coveredPoints = meet[i]; 5114 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5115 PetscCall(PetscFree(closures)); 5116 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5117 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5118 PetscFunctionReturn(PETSC_SUCCESS); 5119 } 5120 5121 /*@ 5122 DMPlexEqual - Determine if two `DM` have the same topology 5123 5124 Not Collective 5125 5126 Input Parameters: 5127 + dmA - A `DMPLEX` object 5128 - dmB - A `DMPLEX` object 5129 5130 Output Parameter: 5131 . equal - `PETSC_TRUE` if the topologies are identical 5132 5133 Level: intermediate 5134 5135 Note: 5136 We are not solving graph isomorphism, so we do not permute. 5137 5138 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5139 @*/ 5140 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5141 { 5142 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5143 5144 PetscFunctionBegin; 5145 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5146 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5147 PetscAssertPointer(equal, 3); 5148 5149 *equal = PETSC_FALSE; 5150 PetscCall(DMPlexGetDepth(dmA, &depth)); 5151 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5152 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5153 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5154 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5155 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5156 for (p = pStart; p < pEnd; ++p) { 5157 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5158 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5159 5160 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5161 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5162 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5163 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5164 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5165 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5166 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5167 for (c = 0; c < coneSize; ++c) { 5168 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5169 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5170 } 5171 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5172 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5173 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5174 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5175 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5176 for (s = 0; s < supportSize; ++s) { 5177 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5178 } 5179 } 5180 *equal = PETSC_TRUE; 5181 PetscFunctionReturn(PETSC_SUCCESS); 5182 } 5183 5184 /*@ 5185 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5186 5187 Not Collective 5188 5189 Input Parameters: 5190 + dm - The `DMPLEX` 5191 . cellDim - The cell dimension 5192 - numCorners - The number of vertices on a cell 5193 5194 Output Parameter: 5195 . numFaceVertices - The number of vertices on a face 5196 5197 Level: developer 5198 5199 Note: 5200 Of course this can only work for a restricted set of symmetric shapes 5201 5202 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5203 @*/ 5204 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5205 { 5206 MPI_Comm comm; 5207 5208 PetscFunctionBegin; 5209 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5210 PetscAssertPointer(numFaceVertices, 4); 5211 switch (cellDim) { 5212 case 0: 5213 *numFaceVertices = 0; 5214 break; 5215 case 1: 5216 *numFaceVertices = 1; 5217 break; 5218 case 2: 5219 switch (numCorners) { 5220 case 3: /* triangle */ 5221 *numFaceVertices = 2; /* Edge has 2 vertices */ 5222 break; 5223 case 4: /* quadrilateral */ 5224 *numFaceVertices = 2; /* Edge has 2 vertices */ 5225 break; 5226 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5227 *numFaceVertices = 3; /* Edge has 3 vertices */ 5228 break; 5229 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5230 *numFaceVertices = 3; /* Edge has 3 vertices */ 5231 break; 5232 default: 5233 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5234 } 5235 break; 5236 case 3: 5237 switch (numCorners) { 5238 case 4: /* tetradehdron */ 5239 *numFaceVertices = 3; /* Face has 3 vertices */ 5240 break; 5241 case 6: /* tet cohesive cells */ 5242 *numFaceVertices = 4; /* Face has 4 vertices */ 5243 break; 5244 case 8: /* hexahedron */ 5245 *numFaceVertices = 4; /* Face has 4 vertices */ 5246 break; 5247 case 9: /* tet cohesive Lagrange cells */ 5248 *numFaceVertices = 6; /* Face has 6 vertices */ 5249 break; 5250 case 10: /* quadratic tetrahedron */ 5251 *numFaceVertices = 6; /* Face has 6 vertices */ 5252 break; 5253 case 12: /* hex cohesive Lagrange cells */ 5254 *numFaceVertices = 6; /* Face has 6 vertices */ 5255 break; 5256 case 18: /* quadratic tet cohesive Lagrange cells */ 5257 *numFaceVertices = 6; /* Face has 6 vertices */ 5258 break; 5259 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5260 *numFaceVertices = 9; /* Face has 9 vertices */ 5261 break; 5262 default: 5263 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5264 } 5265 break; 5266 default: 5267 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5268 } 5269 PetscFunctionReturn(PETSC_SUCCESS); 5270 } 5271 5272 /*@ 5273 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5274 5275 Not Collective 5276 5277 Input Parameter: 5278 . dm - The `DMPLEX` object 5279 5280 Output Parameter: 5281 . depthLabel - The `DMLabel` recording point depth 5282 5283 Level: developer 5284 5285 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5286 @*/ 5287 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5288 { 5289 PetscFunctionBegin; 5290 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5291 PetscAssertPointer(depthLabel, 2); 5292 *depthLabel = dm->depthLabel; 5293 PetscFunctionReturn(PETSC_SUCCESS); 5294 } 5295 5296 /*@ 5297 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5298 5299 Not Collective 5300 5301 Input Parameter: 5302 . dm - The `DMPLEX` object 5303 5304 Output Parameter: 5305 . depth - The number of strata (breadth first levels) in the DAG 5306 5307 Level: developer 5308 5309 Notes: 5310 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5311 5312 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5313 5314 An empty mesh gives -1. 5315 5316 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5317 @*/ 5318 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5319 { 5320 DM_Plex *mesh = (DM_Plex *)dm->data; 5321 DMLabel label; 5322 PetscInt d = -1; 5323 5324 PetscFunctionBegin; 5325 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5326 PetscAssertPointer(depth, 2); 5327 if (mesh->tr) { 5328 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5329 } else { 5330 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5331 // Allow missing depths 5332 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5333 *depth = d; 5334 } 5335 PetscFunctionReturn(PETSC_SUCCESS); 5336 } 5337 5338 /*@ 5339 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5340 5341 Not Collective 5342 5343 Input Parameters: 5344 + dm - The `DMPLEX` object 5345 - depth - The requested depth 5346 5347 Output Parameters: 5348 + start - The first point at this `depth` 5349 - end - One beyond the last point at this `depth` 5350 5351 Level: developer 5352 5353 Notes: 5354 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5355 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5356 higher dimension, e.g., "edges". 5357 5358 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5359 @*/ 5360 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5361 { 5362 DM_Plex *mesh = (DM_Plex *)dm->data; 5363 DMLabel label; 5364 PetscInt pStart, pEnd; 5365 5366 PetscFunctionBegin; 5367 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5368 if (start) { 5369 PetscAssertPointer(start, 3); 5370 *start = 0; 5371 } 5372 if (end) { 5373 PetscAssertPointer(end, 4); 5374 *end = 0; 5375 } 5376 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5377 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5378 if (depth < 0) { 5379 if (start) *start = pStart; 5380 if (end) *end = pEnd; 5381 PetscFunctionReturn(PETSC_SUCCESS); 5382 } 5383 if (mesh->tr) { 5384 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5385 } else { 5386 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5387 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5388 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5389 } 5390 PetscFunctionReturn(PETSC_SUCCESS); 5391 } 5392 5393 /*@ 5394 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5395 5396 Not Collective 5397 5398 Input Parameters: 5399 + dm - The `DMPLEX` object 5400 - height - The requested height 5401 5402 Output Parameters: 5403 + start - The first point at this `height` 5404 - end - One beyond the last point at this `height` 5405 5406 Level: developer 5407 5408 Notes: 5409 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5410 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5411 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5412 5413 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5414 @*/ 5415 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5416 { 5417 DMLabel label; 5418 PetscInt depth, pStart, pEnd; 5419 5420 PetscFunctionBegin; 5421 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5422 if (start) { 5423 PetscAssertPointer(start, 3); 5424 *start = 0; 5425 } 5426 if (end) { 5427 PetscAssertPointer(end, 4); 5428 *end = 0; 5429 } 5430 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5431 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5432 if (height < 0) { 5433 if (start) *start = pStart; 5434 if (end) *end = pEnd; 5435 PetscFunctionReturn(PETSC_SUCCESS); 5436 } 5437 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5438 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5439 else PetscCall(DMGetDimension(dm, &depth)); 5440 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5441 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5442 PetscFunctionReturn(PETSC_SUCCESS); 5443 } 5444 5445 /*@ 5446 DMPlexGetPointDepth - Get the `depth` of a given point 5447 5448 Not Collective 5449 5450 Input Parameters: 5451 + dm - The `DMPLEX` object 5452 - point - The point 5453 5454 Output Parameter: 5455 . depth - The depth of the `point` 5456 5457 Level: intermediate 5458 5459 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5460 @*/ 5461 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5462 { 5463 PetscFunctionBegin; 5464 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5465 PetscAssertPointer(depth, 3); 5466 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5467 PetscFunctionReturn(PETSC_SUCCESS); 5468 } 5469 5470 /*@ 5471 DMPlexGetPointHeight - Get the `height` of a given point 5472 5473 Not Collective 5474 5475 Input Parameters: 5476 + dm - The `DMPLEX` object 5477 - point - The point 5478 5479 Output Parameter: 5480 . height - The height of the `point` 5481 5482 Level: intermediate 5483 5484 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5485 @*/ 5486 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5487 { 5488 PetscInt n, pDepth; 5489 5490 PetscFunctionBegin; 5491 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5492 PetscAssertPointer(height, 3); 5493 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5494 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5495 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5496 PetscFunctionReturn(PETSC_SUCCESS); 5497 } 5498 5499 /*@ 5500 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5501 5502 Not Collective 5503 5504 Input Parameter: 5505 . dm - The `DMPLEX` object 5506 5507 Output Parameter: 5508 . celltypeLabel - The `DMLabel` recording cell polytope type 5509 5510 Level: developer 5511 5512 Note: 5513 This function will trigger automatica computation of cell types. This can be disabled by calling 5514 `DMCreateLabel`(dm, "celltype") beforehand. 5515 5516 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5517 @*/ 5518 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5519 { 5520 PetscFunctionBegin; 5521 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5522 PetscAssertPointer(celltypeLabel, 2); 5523 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5524 *celltypeLabel = dm->celltypeLabel; 5525 PetscFunctionReturn(PETSC_SUCCESS); 5526 } 5527 5528 /*@ 5529 DMPlexGetCellType - Get the polytope type of a given cell 5530 5531 Not Collective 5532 5533 Input Parameters: 5534 + dm - The `DMPLEX` object 5535 - cell - The cell 5536 5537 Output Parameter: 5538 . celltype - The polytope type of the cell 5539 5540 Level: intermediate 5541 5542 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5543 @*/ 5544 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5545 { 5546 DM_Plex *mesh = (DM_Plex *)dm->data; 5547 DMLabel label; 5548 PetscInt ct; 5549 5550 PetscFunctionBegin; 5551 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5552 PetscAssertPointer(celltype, 3); 5553 if (mesh->tr) { 5554 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5555 } else { 5556 PetscInt pStart, pEnd; 5557 5558 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5559 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5560 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5561 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5562 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5563 for (PetscInt p = pStart; p < pEnd; p++) { 5564 PetscCall(DMLabelGetValue(label, p, &ct)); 5565 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5566 } 5567 } 5568 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5569 if (PetscDefined(USE_DEBUG)) { 5570 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5571 PetscCall(DMLabelGetValue(label, cell, &ct)); 5572 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5573 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5574 } 5575 } 5576 PetscFunctionReturn(PETSC_SUCCESS); 5577 } 5578 5579 /*@ 5580 DMPlexSetCellType - Set the polytope type of a given cell 5581 5582 Not Collective 5583 5584 Input Parameters: 5585 + dm - The `DMPLEX` object 5586 . cell - The cell 5587 - celltype - The polytope type of the cell 5588 5589 Level: advanced 5590 5591 Note: 5592 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5593 is executed. This function will override the computed type. However, if automatic classification will not succeed 5594 and a user wants to manually specify all types, the classification must be disabled by calling 5595 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5596 5597 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5598 @*/ 5599 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5600 { 5601 DM_Plex *mesh = (DM_Plex *)dm->data; 5602 DMLabel label; 5603 PetscInt pStart, pEnd; 5604 5605 PetscFunctionBegin; 5606 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5607 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5608 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5609 PetscCall(DMLabelSetValue(label, cell, celltype)); 5610 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5611 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5612 PetscFunctionReturn(PETSC_SUCCESS); 5613 } 5614 5615 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5616 { 5617 PetscSection section; 5618 PetscInt maxHeight; 5619 const char *prefix; 5620 5621 PetscFunctionBegin; 5622 PetscCall(DMClone(dm, cdm)); 5623 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5624 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5625 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5626 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5627 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5628 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5629 PetscCall(DMSetLocalSection(*cdm, section)); 5630 PetscCall(PetscSectionDestroy(§ion)); 5631 5632 PetscCall(DMSetNumFields(*cdm, 1)); 5633 PetscCall(DMCreateDS(*cdm)); 5634 (*cdm)->cloneOpts = PETSC_TRUE; 5635 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5636 PetscFunctionReturn(PETSC_SUCCESS); 5637 } 5638 5639 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5640 { 5641 Vec coordsLocal, cellCoordsLocal; 5642 DM coordsDM, cellCoordsDM; 5643 5644 PetscFunctionBegin; 5645 *field = NULL; 5646 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5647 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5648 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5649 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5650 if (coordsLocal && coordsDM) { 5651 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5652 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5653 } 5654 PetscFunctionReturn(PETSC_SUCCESS); 5655 } 5656 5657 /*@ 5658 DMPlexGetConeSection - Return a section which describes the layout of cone data 5659 5660 Not Collective 5661 5662 Input Parameter: 5663 . dm - The `DMPLEX` object 5664 5665 Output Parameter: 5666 . section - The `PetscSection` object 5667 5668 Level: developer 5669 5670 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5671 @*/ 5672 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5673 { 5674 DM_Plex *mesh = (DM_Plex *)dm->data; 5675 5676 PetscFunctionBegin; 5677 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5678 if (section) *section = mesh->coneSection; 5679 PetscFunctionReturn(PETSC_SUCCESS); 5680 } 5681 5682 /*@ 5683 DMPlexGetSupportSection - Return a section which describes the layout of support data 5684 5685 Not Collective 5686 5687 Input Parameter: 5688 . dm - The `DMPLEX` object 5689 5690 Output Parameter: 5691 . section - The `PetscSection` object 5692 5693 Level: developer 5694 5695 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5696 @*/ 5697 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5698 { 5699 DM_Plex *mesh = (DM_Plex *)dm->data; 5700 5701 PetscFunctionBegin; 5702 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5703 if (section) *section = mesh->supportSection; 5704 PetscFunctionReturn(PETSC_SUCCESS); 5705 } 5706 5707 /*@C 5708 DMPlexGetCones - Return cone data 5709 5710 Not Collective 5711 5712 Input Parameter: 5713 . dm - The `DMPLEX` object 5714 5715 Output Parameter: 5716 . cones - The cone for each point 5717 5718 Level: developer 5719 5720 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5721 @*/ 5722 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5723 { 5724 DM_Plex *mesh = (DM_Plex *)dm->data; 5725 5726 PetscFunctionBegin; 5727 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5728 if (cones) *cones = mesh->cones; 5729 PetscFunctionReturn(PETSC_SUCCESS); 5730 } 5731 5732 /*@C 5733 DMPlexGetConeOrientations - Return cone orientation data 5734 5735 Not Collective 5736 5737 Input Parameter: 5738 . dm - The `DMPLEX` object 5739 5740 Output Parameter: 5741 . coneOrientations - The array of cone orientations for all points 5742 5743 Level: developer 5744 5745 Notes: 5746 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5747 as returned by `DMPlexGetConeOrientation()`. 5748 5749 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5750 5751 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5752 @*/ 5753 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5754 { 5755 DM_Plex *mesh = (DM_Plex *)dm->data; 5756 5757 PetscFunctionBegin; 5758 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5759 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5760 PetscFunctionReturn(PETSC_SUCCESS); 5761 } 5762 5763 /******************************** FEM Support **********************************/ 5764 5765 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5766 { 5767 PetscInt depth; 5768 5769 PetscFunctionBegin; 5770 PetscCall(DMPlexGetDepth(plex, &depth)); 5771 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5772 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5773 PetscFunctionReturn(PETSC_SUCCESS); 5774 } 5775 5776 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5777 { 5778 PetscInt depth; 5779 5780 PetscFunctionBegin; 5781 PetscCall(DMPlexGetDepth(plex, &depth)); 5782 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5783 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5784 PetscFunctionReturn(PETSC_SUCCESS); 5785 } 5786 5787 /* 5788 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5789 representing a line in the section. 5790 */ 5791 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5792 { 5793 PetscObject obj; 5794 PetscClassId id; 5795 PetscFE fe = NULL; 5796 5797 PetscFunctionBeginHot; 5798 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5799 PetscCall(DMGetField(dm, field, NULL, &obj)); 5800 PetscCall(PetscObjectGetClassId(obj, &id)); 5801 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5802 5803 if (!fe) { 5804 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5805 /* An order k SEM disc has k-1 dofs on an edge */ 5806 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5807 *k = *k / *Nc + 1; 5808 } else { 5809 PetscInt dual_space_size, dim; 5810 PetscDualSpace dsp; 5811 5812 PetscCall(DMGetDimension(dm, &dim)); 5813 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5814 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5815 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5816 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5817 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5818 } 5819 PetscFunctionReturn(PETSC_SUCCESS); 5820 } 5821 5822 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5823 { 5824 PetscFunctionBeginHot; 5825 if (tensor) { 5826 *dof = PetscPowInt(k + 1, dim); 5827 } else { 5828 switch (dim) { 5829 case 1: 5830 *dof = k + 1; 5831 break; 5832 case 2: 5833 *dof = ((k + 1) * (k + 2)) / 2; 5834 break; 5835 case 3: 5836 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5837 break; 5838 default: 5839 *dof = 0; 5840 } 5841 } 5842 PetscFunctionReturn(PETSC_SUCCESS); 5843 } 5844 5845 /*@ 5846 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5847 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5848 section provided (or the section of the `DM`). 5849 5850 Input Parameters: 5851 + dm - The `DM` 5852 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5853 - section - The `PetscSection` to reorder, or `NULL` for the default section 5854 5855 Example: 5856 A typical interpolated single-quad mesh might order points as 5857 .vb 5858 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5859 5860 v4 -- e6 -- v3 5861 | | 5862 e7 c0 e8 5863 | | 5864 v1 -- e5 -- v2 5865 .ve 5866 5867 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5868 dofs in the order of points, e.g., 5869 .vb 5870 c0 -> [0,1,2,3] 5871 v1 -> [4] 5872 ... 5873 e5 -> [8, 9] 5874 .ve 5875 5876 which corresponds to the dofs 5877 .vb 5878 6 10 11 7 5879 13 2 3 15 5880 12 0 1 14 5881 4 8 9 5 5882 .ve 5883 5884 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5885 .vb 5886 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5887 .ve 5888 5889 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5890 .vb 5891 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5892 .ve 5893 5894 Level: developer 5895 5896 Notes: 5897 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5898 degree of the basis. 5899 5900 This is required to run with libCEED. 5901 5902 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5903 @*/ 5904 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5905 { 5906 DMLabel label; 5907 PetscInt dim, depth = -1, eStart = -1, Nf; 5908 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5909 5910 PetscFunctionBegin; 5911 PetscCall(DMGetDimension(dm, &dim)); 5912 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5913 if (point < 0) { 5914 PetscInt sStart, sEnd; 5915 5916 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5917 point = sEnd - sStart ? sStart : point; 5918 } 5919 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5920 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5921 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5922 if (depth == 1) { 5923 eStart = point; 5924 } else if (depth == dim) { 5925 const PetscInt *cone; 5926 5927 PetscCall(DMPlexGetCone(dm, point, &cone)); 5928 if (dim == 2) eStart = cone[0]; 5929 else if (dim == 3) { 5930 const PetscInt *cone2; 5931 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5932 eStart = cone2[0]; 5933 } 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); 5934 } 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); 5935 5936 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5937 for (PetscInt d = 1; d <= dim; d++) { 5938 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5939 PetscInt *perm; 5940 5941 for (f = 0; f < Nf; ++f) { 5942 PetscInt dof; 5943 5944 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5945 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5946 if (!continuous && d < dim) continue; 5947 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5948 size += dof * Nc; 5949 } 5950 PetscCall(PetscMalloc1(size, &perm)); 5951 for (f = 0; f < Nf; ++f) { 5952 switch (d) { 5953 case 1: 5954 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5955 if (!continuous && d < dim) continue; 5956 /* 5957 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5958 We want [ vtx0; edge of length k-1; vtx1 ] 5959 */ 5960 if (continuous) { 5961 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5962 for (i = 0; i < k - 1; i++) 5963 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5964 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5965 foffset = offset; 5966 } else { 5967 PetscInt dof; 5968 5969 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5970 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5971 foffset = offset; 5972 } 5973 break; 5974 case 2: 5975 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5976 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5977 if (!continuous && d < dim) continue; 5978 /* The SEM order is 5979 5980 v_lb, {e_b}, v_rb, 5981 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5982 v_lt, reverse {e_t}, v_rt 5983 */ 5984 if (continuous) { 5985 const PetscInt of = 0; 5986 const PetscInt oeb = of + PetscSqr(k - 1); 5987 const PetscInt oer = oeb + (k - 1); 5988 const PetscInt oet = oer + (k - 1); 5989 const PetscInt oel = oet + (k - 1); 5990 const PetscInt ovlb = oel + (k - 1); 5991 const PetscInt ovrb = ovlb + 1; 5992 const PetscInt ovrt = ovrb + 1; 5993 const PetscInt ovlt = ovrt + 1; 5994 PetscInt o; 5995 5996 /* bottom */ 5997 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5998 for (o = oeb; o < oer; ++o) 5999 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6000 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6001 /* middle */ 6002 for (i = 0; i < k - 1; ++i) { 6003 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6004 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6005 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6006 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6007 } 6008 /* top */ 6009 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6010 for (o = oel - 1; o >= oet; --o) 6011 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6012 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6013 foffset = offset; 6014 } else { 6015 PetscInt dof; 6016 6017 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6018 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6019 foffset = offset; 6020 } 6021 break; 6022 case 3: 6023 /* The original hex closure is 6024 6025 {c, 6026 f_b, f_t, f_f, f_b, f_r, f_l, 6027 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6028 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6029 */ 6030 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6031 if (!continuous && d < dim) continue; 6032 /* The SEM order is 6033 Bottom Slice 6034 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6035 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6036 v_blb, {e_bb}, v_brb, 6037 6038 Middle Slice (j) 6039 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6040 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6041 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6042 6043 Top Slice 6044 v_tlf, {e_tf}, v_trf, 6045 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6046 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6047 */ 6048 if (continuous) { 6049 const PetscInt oc = 0; 6050 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6051 const PetscInt oft = ofb + PetscSqr(k - 1); 6052 const PetscInt off = oft + PetscSqr(k - 1); 6053 const PetscInt ofk = off + PetscSqr(k - 1); 6054 const PetscInt ofr = ofk + PetscSqr(k - 1); 6055 const PetscInt ofl = ofr + PetscSqr(k - 1); 6056 const PetscInt oebl = ofl + PetscSqr(k - 1); 6057 const PetscInt oebb = oebl + (k - 1); 6058 const PetscInt oebr = oebb + (k - 1); 6059 const PetscInt oebf = oebr + (k - 1); 6060 const PetscInt oetf = oebf + (k - 1); 6061 const PetscInt oetr = oetf + (k - 1); 6062 const PetscInt oetb = oetr + (k - 1); 6063 const PetscInt oetl = oetb + (k - 1); 6064 const PetscInt oerf = oetl + (k - 1); 6065 const PetscInt oelf = oerf + (k - 1); 6066 const PetscInt oelb = oelf + (k - 1); 6067 const PetscInt oerb = oelb + (k - 1); 6068 const PetscInt ovblf = oerb + (k - 1); 6069 const PetscInt ovblb = ovblf + 1; 6070 const PetscInt ovbrb = ovblb + 1; 6071 const PetscInt ovbrf = ovbrb + 1; 6072 const PetscInt ovtlf = ovbrf + 1; 6073 const PetscInt ovtrf = ovtlf + 1; 6074 const PetscInt ovtrb = ovtrf + 1; 6075 const PetscInt ovtlb = ovtrb + 1; 6076 PetscInt o, n; 6077 6078 /* Bottom Slice */ 6079 /* bottom */ 6080 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6081 for (o = oetf - 1; o >= oebf; --o) 6082 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6083 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6084 /* middle */ 6085 for (i = 0; i < k - 1; ++i) { 6086 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6087 for (n = 0; n < k - 1; ++n) { 6088 o = ofb + n * (k - 1) + i; 6089 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6090 } 6091 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6092 } 6093 /* top */ 6094 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6095 for (o = oebb; o < oebr; ++o) 6096 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6097 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6098 6099 /* Middle Slice */ 6100 for (j = 0; j < k - 1; ++j) { 6101 /* bottom */ 6102 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6103 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6104 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6105 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6106 /* middle */ 6107 for (i = 0; i < k - 1; ++i) { 6108 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6109 for (n = 0; n < k - 1; ++n) 6110 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6111 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6112 } 6113 /* top */ 6114 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6115 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6116 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6117 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6118 } 6119 6120 /* Top Slice */ 6121 /* bottom */ 6122 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6123 for (o = oetf; o < oetr; ++o) 6124 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6125 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6126 /* middle */ 6127 for (i = 0; i < k - 1; ++i) { 6128 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6129 for (n = 0; n < k - 1; ++n) 6130 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6131 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6132 } 6133 /* top */ 6134 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6135 for (o = oetl - 1; o >= oetb; --o) 6136 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6137 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6138 6139 foffset = offset; 6140 } else { 6141 PetscInt dof; 6142 6143 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6144 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6145 foffset = offset; 6146 } 6147 break; 6148 default: 6149 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6150 } 6151 } 6152 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6153 /* Check permutation */ 6154 { 6155 PetscInt *check; 6156 6157 PetscCall(PetscMalloc1(size, &check)); 6158 for (i = 0; i < size; ++i) { 6159 check[i] = -1; 6160 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6161 } 6162 for (i = 0; i < size; ++i) check[perm[i]] = i; 6163 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6164 PetscCall(PetscFree(check)); 6165 } 6166 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6167 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6168 PetscInt *loc_perm; 6169 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6170 for (PetscInt i = 0; i < size; i++) { 6171 loc_perm[i] = perm[i]; 6172 loc_perm[size + i] = size + perm[i]; 6173 } 6174 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6175 } 6176 } 6177 PetscFunctionReturn(PETSC_SUCCESS); 6178 } 6179 6180 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6181 { 6182 PetscDS prob; 6183 PetscInt depth, Nf, h; 6184 DMLabel label; 6185 6186 PetscFunctionBeginHot; 6187 PetscCall(DMGetDS(dm, &prob)); 6188 Nf = prob->Nf; 6189 label = dm->depthLabel; 6190 *dspace = NULL; 6191 if (field < Nf) { 6192 PetscObject disc = prob->disc[field]; 6193 6194 if (disc->classid == PETSCFE_CLASSID) { 6195 PetscDualSpace dsp; 6196 6197 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6198 PetscCall(DMLabelGetNumValues(label, &depth)); 6199 PetscCall(DMLabelGetValue(label, point, &h)); 6200 h = depth - 1 - h; 6201 if (h) { 6202 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6203 } else { 6204 *dspace = dsp; 6205 } 6206 } 6207 } 6208 PetscFunctionReturn(PETSC_SUCCESS); 6209 } 6210 6211 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6212 { 6213 PetscScalar *array; 6214 const PetscScalar *vArray; 6215 const PetscInt *cone, *coneO; 6216 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6217 6218 PetscFunctionBeginHot; 6219 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6220 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6221 PetscCall(DMPlexGetCone(dm, point, &cone)); 6222 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6223 if (!values || !*values) { 6224 if ((point >= pStart) && (point < pEnd)) { 6225 PetscInt dof; 6226 6227 PetscCall(PetscSectionGetDof(section, point, &dof)); 6228 size += dof; 6229 } 6230 for (p = 0; p < numPoints; ++p) { 6231 const PetscInt cp = cone[p]; 6232 PetscInt dof; 6233 6234 if ((cp < pStart) || (cp >= pEnd)) continue; 6235 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6236 size += dof; 6237 } 6238 if (!values) { 6239 if (csize) *csize = size; 6240 PetscFunctionReturn(PETSC_SUCCESS); 6241 } 6242 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6243 } else { 6244 array = *values; 6245 } 6246 size = 0; 6247 PetscCall(VecGetArrayRead(v, &vArray)); 6248 if ((point >= pStart) && (point < pEnd)) { 6249 PetscInt dof, off, d; 6250 const PetscScalar *varr; 6251 6252 PetscCall(PetscSectionGetDof(section, point, &dof)); 6253 PetscCall(PetscSectionGetOffset(section, point, &off)); 6254 varr = PetscSafePointerPlusOffset(vArray, off); 6255 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6256 size += dof; 6257 } 6258 for (p = 0; p < numPoints; ++p) { 6259 const PetscInt cp = cone[p]; 6260 PetscInt o = coneO[p]; 6261 PetscInt dof, off, d; 6262 const PetscScalar *varr; 6263 6264 if ((cp < pStart) || (cp >= pEnd)) continue; 6265 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6266 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6267 varr = PetscSafePointerPlusOffset(vArray, off); 6268 if (o >= 0) { 6269 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6270 } else { 6271 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6272 } 6273 size += dof; 6274 } 6275 PetscCall(VecRestoreArrayRead(v, &vArray)); 6276 if (!*values) { 6277 if (csize) *csize = size; 6278 *values = array; 6279 } else { 6280 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6281 *csize = size; 6282 } 6283 PetscFunctionReturn(PETSC_SUCCESS); 6284 } 6285 6286 /* Compress out points not in the section */ 6287 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6288 { 6289 const PetscInt np = *numPoints; 6290 PetscInt pStart, pEnd, p, q; 6291 6292 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6293 for (p = 0, q = 0; p < np; ++p) { 6294 const PetscInt r = points[p * 2]; 6295 if ((r >= pStart) && (r < pEnd)) { 6296 points[q * 2] = r; 6297 points[q * 2 + 1] = points[p * 2 + 1]; 6298 ++q; 6299 } 6300 } 6301 *numPoints = q; 6302 return PETSC_SUCCESS; 6303 } 6304 6305 /* Compressed closure does not apply closure permutation */ 6306 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6307 { 6308 const PetscInt *cla = NULL; 6309 PetscInt np, *pts = NULL; 6310 6311 PetscFunctionBeginHot; 6312 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6313 if (!ornt && *clPoints) { 6314 PetscInt dof, off; 6315 6316 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6317 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6318 PetscCall(ISGetIndices(*clPoints, &cla)); 6319 np = dof / 2; 6320 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6321 } else { 6322 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6323 PetscCall(CompressPoints_Private(section, &np, pts)); 6324 } 6325 *numPoints = np; 6326 *points = pts; 6327 *clp = cla; 6328 PetscFunctionReturn(PETSC_SUCCESS); 6329 } 6330 6331 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6332 { 6333 PetscFunctionBeginHot; 6334 if (!*clPoints) { 6335 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6336 } else { 6337 PetscCall(ISRestoreIndices(*clPoints, clp)); 6338 } 6339 *numPoints = 0; 6340 *points = NULL; 6341 *clSec = NULL; 6342 *clPoints = NULL; 6343 *clp = NULL; 6344 PetscFunctionReturn(PETSC_SUCCESS); 6345 } 6346 6347 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6348 { 6349 PetscInt offset = 0, p; 6350 const PetscInt **perms = NULL; 6351 const PetscScalar **flips = NULL; 6352 6353 PetscFunctionBeginHot; 6354 *size = 0; 6355 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6356 for (p = 0; p < numPoints; p++) { 6357 const PetscInt point = points[2 * p]; 6358 const PetscInt *perm = perms ? perms[p] : NULL; 6359 const PetscScalar *flip = flips ? flips[p] : NULL; 6360 PetscInt dof, off, d; 6361 const PetscScalar *varr; 6362 6363 PetscCall(PetscSectionGetDof(section, point, &dof)); 6364 PetscCall(PetscSectionGetOffset(section, point, &off)); 6365 varr = PetscSafePointerPlusOffset(vArray, off); 6366 if (clperm) { 6367 if (perm) { 6368 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6369 } else { 6370 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6371 } 6372 if (flip) { 6373 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6374 } 6375 } else { 6376 if (perm) { 6377 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6378 } else { 6379 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6380 } 6381 if (flip) { 6382 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6383 } 6384 } 6385 offset += dof; 6386 } 6387 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6388 *size = offset; 6389 PetscFunctionReturn(PETSC_SUCCESS); 6390 } 6391 6392 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[]) 6393 { 6394 PetscInt offset = 0, f; 6395 6396 PetscFunctionBeginHot; 6397 *size = 0; 6398 for (f = 0; f < numFields; ++f) { 6399 PetscInt p; 6400 const PetscInt **perms = NULL; 6401 const PetscScalar **flips = NULL; 6402 6403 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6404 for (p = 0; p < numPoints; p++) { 6405 const PetscInt point = points[2 * p]; 6406 PetscInt fdof, foff, b; 6407 const PetscScalar *varr; 6408 const PetscInt *perm = perms ? perms[p] : NULL; 6409 const PetscScalar *flip = flips ? flips[p] : NULL; 6410 6411 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6412 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6413 varr = &vArray[foff]; 6414 if (clperm) { 6415 if (perm) { 6416 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6417 } else { 6418 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6419 } 6420 if (flip) { 6421 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6422 } 6423 } else { 6424 if (perm) { 6425 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6426 } else { 6427 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6428 } 6429 if (flip) { 6430 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6431 } 6432 } 6433 offset += fdof; 6434 } 6435 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6436 } 6437 *size = offset; 6438 PetscFunctionReturn(PETSC_SUCCESS); 6439 } 6440 6441 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6442 { 6443 PetscSection clSection; 6444 IS clPoints; 6445 PetscInt *points = NULL; 6446 const PetscInt *clp, *perm = NULL; 6447 PetscInt depth, numFields, numPoints, asize; 6448 6449 PetscFunctionBeginHot; 6450 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6451 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6452 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6453 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6454 PetscCall(DMPlexGetDepth(dm, &depth)); 6455 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6456 if (depth == 1 && numFields < 2) { 6457 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6458 PetscFunctionReturn(PETSC_SUCCESS); 6459 } 6460 /* Get points */ 6461 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6462 /* Get sizes */ 6463 asize = 0; 6464 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6465 PetscInt dof; 6466 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6467 asize += dof; 6468 } 6469 if (values) { 6470 const PetscScalar *vArray; 6471 PetscInt size; 6472 6473 if (*values) { 6474 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); 6475 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6476 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6477 PetscCall(VecGetArrayRead(v, &vArray)); 6478 /* Get values */ 6479 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6480 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6481 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6482 /* Cleanup array */ 6483 PetscCall(VecRestoreArrayRead(v, &vArray)); 6484 } 6485 if (csize) *csize = asize; 6486 /* Cleanup points */ 6487 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6488 PetscFunctionReturn(PETSC_SUCCESS); 6489 } 6490 6491 /*@C 6492 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6493 6494 Not collective 6495 6496 Input Parameters: 6497 + dm - The `DM` 6498 . section - The section describing the layout in `v`, or `NULL` to use the default section 6499 . v - The local vector 6500 - point - The point in the `DM` 6501 6502 Input/Output Parameters: 6503 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6504 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6505 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6506 6507 Level: intermediate 6508 6509 Notes: 6510 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6511 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6512 assembly function, and a user may already have allocated storage for this operation. 6513 6514 A typical use could be 6515 .vb 6516 values = NULL; 6517 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6518 for (cl = 0; cl < clSize; ++cl) { 6519 <Compute on closure> 6520 } 6521 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6522 .ve 6523 or 6524 .vb 6525 PetscMalloc1(clMaxSize, &values); 6526 for (p = pStart; p < pEnd; ++p) { 6527 clSize = clMaxSize; 6528 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6529 for (cl = 0; cl < clSize; ++cl) { 6530 <Compute on closure> 6531 } 6532 } 6533 PetscFree(values); 6534 .ve 6535 6536 Fortran Notes: 6537 The `csize` argument is not present in the Fortran binding. 6538 6539 `values` must be declared with 6540 .vb 6541 PetscScalar,dimension(:),pointer :: values 6542 .ve 6543 and it will be allocated internally by PETSc to hold the values returned 6544 6545 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6546 @*/ 6547 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6548 { 6549 PetscFunctionBeginHot; 6550 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6551 PetscFunctionReturn(PETSC_SUCCESS); 6552 } 6553 6554 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6555 { 6556 DMLabel depthLabel; 6557 PetscSection clSection; 6558 IS clPoints; 6559 PetscScalar *array; 6560 const PetscScalar *vArray; 6561 PetscInt *points = NULL; 6562 const PetscInt *clp, *perm = NULL; 6563 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6564 6565 PetscFunctionBeginHot; 6566 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6567 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6568 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6569 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6570 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6571 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6572 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6573 if (mdepth == 1 && numFields < 2) { 6574 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6575 PetscFunctionReturn(PETSC_SUCCESS); 6576 } 6577 /* Get points */ 6578 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6579 for (clsize = 0, p = 0; p < Np; p++) { 6580 PetscInt dof; 6581 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6582 clsize += dof; 6583 } 6584 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6585 /* Filter points */ 6586 for (p = 0; p < numPoints * 2; p += 2) { 6587 PetscInt dep; 6588 6589 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6590 if (dep != depth) continue; 6591 points[Np * 2 + 0] = points[p]; 6592 points[Np * 2 + 1] = points[p + 1]; 6593 ++Np; 6594 } 6595 /* Get array */ 6596 if (!values || !*values) { 6597 PetscInt asize = 0, dof; 6598 6599 for (p = 0; p < Np * 2; p += 2) { 6600 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6601 asize += dof; 6602 } 6603 if (!values) { 6604 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6605 if (csize) *csize = asize; 6606 PetscFunctionReturn(PETSC_SUCCESS); 6607 } 6608 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6609 } else { 6610 array = *values; 6611 } 6612 PetscCall(VecGetArrayRead(v, &vArray)); 6613 /* Get values */ 6614 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6615 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6616 /* Cleanup points */ 6617 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6618 /* Cleanup array */ 6619 PetscCall(VecRestoreArrayRead(v, &vArray)); 6620 if (!*values) { 6621 if (csize) *csize = size; 6622 *values = array; 6623 } else { 6624 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6625 *csize = size; 6626 } 6627 PetscFunctionReturn(PETSC_SUCCESS); 6628 } 6629 6630 /*@C 6631 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6632 6633 Not collective 6634 6635 Input Parameters: 6636 + dm - The `DM` 6637 . section - The section describing the layout in `v`, or `NULL` to use the default section 6638 . v - The local vector 6639 . point - The point in the `DM` 6640 . csize - The number of values in the closure, or `NULL` 6641 - values - The array of values 6642 6643 Level: intermediate 6644 6645 Note: 6646 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6647 6648 Fortran Note: 6649 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6650 6651 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6652 @*/ 6653 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6654 { 6655 PetscInt size = 0; 6656 6657 PetscFunctionBegin; 6658 /* Should work without recalculating size */ 6659 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6660 *values = NULL; 6661 PetscFunctionReturn(PETSC_SUCCESS); 6662 } 6663 6664 static inline void add(PetscScalar *x, PetscScalar y) 6665 { 6666 *x += y; 6667 } 6668 static inline void insert(PetscScalar *x, PetscScalar y) 6669 { 6670 *x = y; 6671 } 6672 6673 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[]) 6674 { 6675 PetscInt cdof; /* The number of constraints on this point */ 6676 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6677 PetscScalar *a; 6678 PetscInt off, cind = 0, k; 6679 6680 PetscFunctionBegin; 6681 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6682 PetscCall(PetscSectionGetOffset(section, point, &off)); 6683 a = &array[off]; 6684 if (!cdof || setBC) { 6685 if (clperm) { 6686 if (perm) { 6687 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6688 } else { 6689 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6690 } 6691 } else { 6692 if (perm) { 6693 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6694 } else { 6695 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6696 } 6697 } 6698 } else { 6699 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6700 if (clperm) { 6701 if (perm) { 6702 for (k = 0; k < dof; ++k) { 6703 if ((cind < cdof) && (k == cdofs[cind])) { 6704 ++cind; 6705 continue; 6706 } 6707 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6708 } 6709 } else { 6710 for (k = 0; k < dof; ++k) { 6711 if ((cind < cdof) && (k == cdofs[cind])) { 6712 ++cind; 6713 continue; 6714 } 6715 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6716 } 6717 } 6718 } else { 6719 if (perm) { 6720 for (k = 0; k < dof; ++k) { 6721 if ((cind < cdof) && (k == cdofs[cind])) { 6722 ++cind; 6723 continue; 6724 } 6725 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6726 } 6727 } else { 6728 for (k = 0; k < dof; ++k) { 6729 if ((cind < cdof) && (k == cdofs[cind])) { 6730 ++cind; 6731 continue; 6732 } 6733 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6734 } 6735 } 6736 } 6737 } 6738 PetscFunctionReturn(PETSC_SUCCESS); 6739 } 6740 6741 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[]) 6742 { 6743 PetscInt cdof; /* The number of constraints on this point */ 6744 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6745 PetscScalar *a; 6746 PetscInt off, cind = 0, k; 6747 6748 PetscFunctionBegin; 6749 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6750 PetscCall(PetscSectionGetOffset(section, point, &off)); 6751 a = &array[off]; 6752 if (cdof) { 6753 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6754 if (clperm) { 6755 if (perm) { 6756 for (k = 0; k < dof; ++k) { 6757 if ((cind < cdof) && (k == cdofs[cind])) { 6758 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6759 cind++; 6760 } 6761 } 6762 } else { 6763 for (k = 0; k < dof; ++k) { 6764 if ((cind < cdof) && (k == cdofs[cind])) { 6765 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6766 cind++; 6767 } 6768 } 6769 } 6770 } else { 6771 if (perm) { 6772 for (k = 0; k < dof; ++k) { 6773 if ((cind < cdof) && (k == cdofs[cind])) { 6774 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6775 cind++; 6776 } 6777 } 6778 } else { 6779 for (k = 0; k < dof; ++k) { 6780 if ((cind < cdof) && (k == cdofs[cind])) { 6781 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6782 cind++; 6783 } 6784 } 6785 } 6786 } 6787 } 6788 PetscFunctionReturn(PETSC_SUCCESS); 6789 } 6790 6791 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[]) 6792 { 6793 PetscScalar *a; 6794 PetscInt fdof, foff, fcdof, foffset = *offset; 6795 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6796 PetscInt cind = 0, b; 6797 6798 PetscFunctionBegin; 6799 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6800 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6801 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6802 a = &array[foff]; 6803 if (!fcdof || setBC) { 6804 if (clperm) { 6805 if (perm) { 6806 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6807 } else { 6808 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6809 } 6810 } else { 6811 if (perm) { 6812 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6813 } else { 6814 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6815 } 6816 } 6817 } else { 6818 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6819 if (clperm) { 6820 if (perm) { 6821 for (b = 0; b < fdof; b++) { 6822 if ((cind < fcdof) && (b == fcdofs[cind])) { 6823 ++cind; 6824 continue; 6825 } 6826 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6827 } 6828 } else { 6829 for (b = 0; b < fdof; b++) { 6830 if ((cind < fcdof) && (b == fcdofs[cind])) { 6831 ++cind; 6832 continue; 6833 } 6834 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6835 } 6836 } 6837 } else { 6838 if (perm) { 6839 for (b = 0; b < fdof; b++) { 6840 if ((cind < fcdof) && (b == fcdofs[cind])) { 6841 ++cind; 6842 continue; 6843 } 6844 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6845 } 6846 } else { 6847 for (b = 0; b < fdof; b++) { 6848 if ((cind < fcdof) && (b == fcdofs[cind])) { 6849 ++cind; 6850 continue; 6851 } 6852 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6853 } 6854 } 6855 } 6856 } 6857 *offset += fdof; 6858 PetscFunctionReturn(PETSC_SUCCESS); 6859 } 6860 6861 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[]) 6862 { 6863 PetscScalar *a; 6864 PetscInt fdof, foff, fcdof, foffset = *offset; 6865 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6866 PetscInt Nc, cind = 0, ncind = 0, b; 6867 PetscBool ncSet, fcSet; 6868 6869 PetscFunctionBegin; 6870 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6871 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6872 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6873 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6874 a = &array[foff]; 6875 if (fcdof) { 6876 /* We just override fcdof and fcdofs with Ncc and comps */ 6877 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6878 if (clperm) { 6879 if (perm) { 6880 if (comps) { 6881 for (b = 0; b < fdof; b++) { 6882 ncSet = fcSet = PETSC_FALSE; 6883 if (b % Nc == comps[ncind]) { 6884 ncind = (ncind + 1) % Ncc; 6885 ncSet = PETSC_TRUE; 6886 } 6887 if ((cind < fcdof) && (b == fcdofs[cind])) { 6888 ++cind; 6889 fcSet = PETSC_TRUE; 6890 } 6891 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6892 } 6893 } else { 6894 for (b = 0; b < fdof; b++) { 6895 if ((cind < fcdof) && (b == fcdofs[cind])) { 6896 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6897 ++cind; 6898 } 6899 } 6900 } 6901 } else { 6902 if (comps) { 6903 for (b = 0; b < fdof; b++) { 6904 ncSet = fcSet = PETSC_FALSE; 6905 if (b % Nc == comps[ncind]) { 6906 ncind = (ncind + 1) % Ncc; 6907 ncSet = PETSC_TRUE; 6908 } 6909 if ((cind < fcdof) && (b == fcdofs[cind])) { 6910 ++cind; 6911 fcSet = PETSC_TRUE; 6912 } 6913 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6914 } 6915 } else { 6916 for (b = 0; b < fdof; b++) { 6917 if ((cind < fcdof) && (b == fcdofs[cind])) { 6918 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6919 ++cind; 6920 } 6921 } 6922 } 6923 } 6924 } else { 6925 if (perm) { 6926 if (comps) { 6927 for (b = 0; b < fdof; b++) { 6928 ncSet = fcSet = PETSC_FALSE; 6929 if (b % Nc == comps[ncind]) { 6930 ncind = (ncind + 1) % Ncc; 6931 ncSet = PETSC_TRUE; 6932 } 6933 if ((cind < fcdof) && (b == fcdofs[cind])) { 6934 ++cind; 6935 fcSet = PETSC_TRUE; 6936 } 6937 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6938 } 6939 } else { 6940 for (b = 0; b < fdof; b++) { 6941 if ((cind < fcdof) && (b == fcdofs[cind])) { 6942 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6943 ++cind; 6944 } 6945 } 6946 } 6947 } else { 6948 if (comps) { 6949 for (b = 0; b < fdof; b++) { 6950 ncSet = fcSet = PETSC_FALSE; 6951 if (b % Nc == comps[ncind]) { 6952 ncind = (ncind + 1) % Ncc; 6953 ncSet = PETSC_TRUE; 6954 } 6955 if ((cind < fcdof) && (b == fcdofs[cind])) { 6956 ++cind; 6957 fcSet = PETSC_TRUE; 6958 } 6959 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6960 } 6961 } else { 6962 for (b = 0; b < fdof; b++) { 6963 if ((cind < fcdof) && (b == fcdofs[cind])) { 6964 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6965 ++cind; 6966 } 6967 } 6968 } 6969 } 6970 } 6971 } 6972 *offset += fdof; 6973 PetscFunctionReturn(PETSC_SUCCESS); 6974 } 6975 6976 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6977 { 6978 PetscScalar *array; 6979 const PetscInt *cone, *coneO; 6980 PetscInt pStart, pEnd, p, numPoints, off, dof; 6981 6982 PetscFunctionBeginHot; 6983 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6984 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6985 PetscCall(DMPlexGetCone(dm, point, &cone)); 6986 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6987 PetscCall(VecGetArray(v, &array)); 6988 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6989 const PetscInt cp = !p ? point : cone[p - 1]; 6990 const PetscInt o = !p ? 0 : coneO[p - 1]; 6991 6992 if ((cp < pStart) || (cp >= pEnd)) { 6993 dof = 0; 6994 continue; 6995 } 6996 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6997 /* ADD_VALUES */ 6998 { 6999 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7000 PetscScalar *a; 7001 PetscInt cdof, coff, cind = 0, k; 7002 7003 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7004 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7005 a = &array[coff]; 7006 if (!cdof) { 7007 if (o >= 0) { 7008 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7009 } else { 7010 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7011 } 7012 } else { 7013 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7014 if (o >= 0) { 7015 for (k = 0; k < dof; ++k) { 7016 if ((cind < cdof) && (k == cdofs[cind])) { 7017 ++cind; 7018 continue; 7019 } 7020 a[k] += values[off + k]; 7021 } 7022 } else { 7023 for (k = 0; k < dof; ++k) { 7024 if ((cind < cdof) && (k == cdofs[cind])) { 7025 ++cind; 7026 continue; 7027 } 7028 a[k] += values[off + dof - k - 1]; 7029 } 7030 } 7031 } 7032 } 7033 } 7034 PetscCall(VecRestoreArray(v, &array)); 7035 PetscFunctionReturn(PETSC_SUCCESS); 7036 } 7037 7038 /*@C 7039 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7040 7041 Not collective 7042 7043 Input Parameters: 7044 + dm - The `DM` 7045 . section - The section describing the layout in `v`, or `NULL` to use the default section 7046 . v - The local vector 7047 . point - The point in the `DM` 7048 . values - The array of values 7049 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7050 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7051 7052 Level: intermediate 7053 7054 Note: 7055 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7056 7057 Fortran Note: 7058 `values` must be declared with 7059 .vb 7060 PetscScalar,dimension(:),pointer :: values 7061 .ve 7062 7063 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7064 @*/ 7065 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7066 { 7067 PetscSection clSection; 7068 IS clPoints; 7069 PetscScalar *array; 7070 PetscInt *points = NULL; 7071 const PetscInt *clp, *clperm = NULL; 7072 PetscInt depth, numFields, numPoints, p, clsize; 7073 7074 PetscFunctionBeginHot; 7075 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7076 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7077 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7078 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7079 PetscCall(DMPlexGetDepth(dm, &depth)); 7080 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7081 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7082 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7083 PetscFunctionReturn(PETSC_SUCCESS); 7084 } 7085 /* Get points */ 7086 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7087 for (clsize = 0, p = 0; p < numPoints; p++) { 7088 PetscInt dof; 7089 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7090 clsize += dof; 7091 } 7092 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7093 /* Get array */ 7094 PetscCall(VecGetArray(v, &array)); 7095 /* Get values */ 7096 if (numFields > 0) { 7097 PetscInt offset = 0, f; 7098 for (f = 0; f < numFields; ++f) { 7099 const PetscInt **perms = NULL; 7100 const PetscScalar **flips = NULL; 7101 7102 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7103 switch (mode) { 7104 case INSERT_VALUES: 7105 for (p = 0; p < numPoints; p++) { 7106 const PetscInt point = points[2 * p]; 7107 const PetscInt *perm = perms ? perms[p] : NULL; 7108 const PetscScalar *flip = flips ? flips[p] : NULL; 7109 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7110 } 7111 break; 7112 case INSERT_ALL_VALUES: 7113 for (p = 0; p < numPoints; p++) { 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(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7118 } 7119 break; 7120 case INSERT_BC_VALUES: 7121 for (p = 0; p < numPoints; p++) { 7122 const PetscInt point = points[2 * p]; 7123 const PetscInt *perm = perms ? perms[p] : NULL; 7124 const PetscScalar *flip = flips ? flips[p] : NULL; 7125 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7126 } 7127 break; 7128 case ADD_VALUES: 7129 for (p = 0; p < numPoints; p++) { 7130 const PetscInt point = points[2 * p]; 7131 const PetscInt *perm = perms ? perms[p] : NULL; 7132 const PetscScalar *flip = flips ? flips[p] : NULL; 7133 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7134 } 7135 break; 7136 case ADD_ALL_VALUES: 7137 for (p = 0; p < numPoints; p++) { 7138 const PetscInt point = points[2 * p]; 7139 const PetscInt *perm = perms ? perms[p] : NULL; 7140 const PetscScalar *flip = flips ? flips[p] : NULL; 7141 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7142 } 7143 break; 7144 case ADD_BC_VALUES: 7145 for (p = 0; p < numPoints; p++) { 7146 const PetscInt point = points[2 * p]; 7147 const PetscInt *perm = perms ? perms[p] : NULL; 7148 const PetscScalar *flip = flips ? flips[p] : NULL; 7149 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7150 } 7151 break; 7152 default: 7153 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7154 } 7155 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7156 } 7157 } else { 7158 PetscInt dof, off; 7159 const PetscInt **perms = NULL; 7160 const PetscScalar **flips = NULL; 7161 7162 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7163 switch (mode) { 7164 case INSERT_VALUES: 7165 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7166 const PetscInt point = points[2 * p]; 7167 const PetscInt *perm = perms ? perms[p] : NULL; 7168 const PetscScalar *flip = flips ? flips[p] : NULL; 7169 PetscCall(PetscSectionGetDof(section, point, &dof)); 7170 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7171 } 7172 break; 7173 case INSERT_ALL_VALUES: 7174 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7175 const PetscInt point = points[2 * p]; 7176 const PetscInt *perm = perms ? perms[p] : NULL; 7177 const PetscScalar *flip = flips ? flips[p] : NULL; 7178 PetscCall(PetscSectionGetDof(section, point, &dof)); 7179 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7180 } 7181 break; 7182 case INSERT_BC_VALUES: 7183 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7184 const PetscInt point = points[2 * p]; 7185 const PetscInt *perm = perms ? perms[p] : NULL; 7186 const PetscScalar *flip = flips ? flips[p] : NULL; 7187 PetscCall(PetscSectionGetDof(section, point, &dof)); 7188 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7189 } 7190 break; 7191 case ADD_VALUES: 7192 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7193 const PetscInt point = points[2 * p]; 7194 const PetscInt *perm = perms ? perms[p] : NULL; 7195 const PetscScalar *flip = flips ? flips[p] : NULL; 7196 PetscCall(PetscSectionGetDof(section, point, &dof)); 7197 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7198 } 7199 break; 7200 case ADD_ALL_VALUES: 7201 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7202 const PetscInt point = points[2 * p]; 7203 const PetscInt *perm = perms ? perms[p] : NULL; 7204 const PetscScalar *flip = flips ? flips[p] : NULL; 7205 PetscCall(PetscSectionGetDof(section, point, &dof)); 7206 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7207 } 7208 break; 7209 case ADD_BC_VALUES: 7210 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7211 const PetscInt point = points[2 * p]; 7212 const PetscInt *perm = perms ? perms[p] : NULL; 7213 const PetscScalar *flip = flips ? flips[p] : NULL; 7214 PetscCall(PetscSectionGetDof(section, point, &dof)); 7215 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7216 } 7217 break; 7218 default: 7219 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7220 } 7221 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7222 } 7223 /* Cleanup points */ 7224 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7225 /* Cleanup array */ 7226 PetscCall(VecRestoreArray(v, &array)); 7227 PetscFunctionReturn(PETSC_SUCCESS); 7228 } 7229 7230 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7231 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7232 { 7233 PetscFunctionBegin; 7234 *contains = PETSC_TRUE; 7235 if (label) { 7236 PetscInt fdof; 7237 7238 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7239 if (!*contains) { 7240 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7241 *offset += fdof; 7242 PetscFunctionReturn(PETSC_SUCCESS); 7243 } 7244 } 7245 PetscFunctionReturn(PETSC_SUCCESS); 7246 } 7247 7248 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7249 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) 7250 { 7251 PetscSection clSection; 7252 IS clPoints; 7253 PetscScalar *array; 7254 PetscInt *points = NULL; 7255 const PetscInt *clp; 7256 PetscInt numFields, numPoints, p; 7257 PetscInt offset = 0, f; 7258 7259 PetscFunctionBeginHot; 7260 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7261 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7262 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7263 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7264 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7265 /* Get points */ 7266 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7267 /* Get array */ 7268 PetscCall(VecGetArray(v, &array)); 7269 /* Get values */ 7270 for (f = 0; f < numFields; ++f) { 7271 const PetscInt **perms = NULL; 7272 const PetscScalar **flips = NULL; 7273 PetscBool contains; 7274 7275 if (!fieldActive[f]) { 7276 for (p = 0; p < numPoints * 2; p += 2) { 7277 PetscInt fdof; 7278 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7279 offset += fdof; 7280 } 7281 continue; 7282 } 7283 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7284 switch (mode) { 7285 case INSERT_VALUES: 7286 for (p = 0; p < numPoints; p++) { 7287 const PetscInt point = points[2 * p]; 7288 const PetscInt *perm = perms ? perms[p] : NULL; 7289 const PetscScalar *flip = flips ? flips[p] : NULL; 7290 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7291 if (!contains) continue; 7292 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7293 } 7294 break; 7295 case INSERT_ALL_VALUES: 7296 for (p = 0; p < numPoints; p++) { 7297 const PetscInt point = points[2 * p]; 7298 const PetscInt *perm = perms ? perms[p] : NULL; 7299 const PetscScalar *flip = flips ? flips[p] : NULL; 7300 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7301 if (!contains) continue; 7302 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7303 } 7304 break; 7305 case INSERT_BC_VALUES: 7306 for (p = 0; p < numPoints; p++) { 7307 const PetscInt point = points[2 * p]; 7308 const PetscInt *perm = perms ? perms[p] : NULL; 7309 const PetscScalar *flip = flips ? flips[p] : NULL; 7310 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7311 if (!contains) continue; 7312 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7313 } 7314 break; 7315 case ADD_VALUES: 7316 for (p = 0; p < numPoints; p++) { 7317 const PetscInt point = points[2 * p]; 7318 const PetscInt *perm = perms ? perms[p] : NULL; 7319 const PetscScalar *flip = flips ? flips[p] : NULL; 7320 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7321 if (!contains) continue; 7322 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7323 } 7324 break; 7325 case ADD_ALL_VALUES: 7326 for (p = 0; p < numPoints; p++) { 7327 const PetscInt point = points[2 * p]; 7328 const PetscInt *perm = perms ? perms[p] : NULL; 7329 const PetscScalar *flip = flips ? flips[p] : NULL; 7330 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7331 if (!contains) continue; 7332 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7333 } 7334 break; 7335 default: 7336 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7337 } 7338 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7339 } 7340 /* Cleanup points */ 7341 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7342 /* Cleanup array */ 7343 PetscCall(VecRestoreArray(v, &array)); 7344 PetscFunctionReturn(PETSC_SUCCESS); 7345 } 7346 7347 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7348 { 7349 PetscMPIInt rank; 7350 PetscInt i, j; 7351 7352 PetscFunctionBegin; 7353 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7354 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7355 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7356 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7357 numCIndices = numCIndices ? numCIndices : numRIndices; 7358 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7359 for (i = 0; i < numRIndices; i++) { 7360 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7361 for (j = 0; j < numCIndices; j++) { 7362 #if defined(PETSC_USE_COMPLEX) 7363 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7364 #else 7365 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7366 #endif 7367 } 7368 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7369 } 7370 PetscFunctionReturn(PETSC_SUCCESS); 7371 } 7372 7373 /* 7374 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7375 7376 Input Parameters: 7377 + section - The section for this data layout 7378 . islocal - Is the section (and thus indices being requested) local or global? 7379 . point - The point contributing dofs with these indices 7380 . off - The global offset of this point 7381 . loff - The local offset of each field 7382 . setBC - The flag determining whether to include indices of boundary values 7383 . perm - A permutation of the dofs on this point, or NULL 7384 - indperm - A permutation of the entire indices array, or NULL 7385 7386 Output Parameter: 7387 . indices - Indices for dofs on this point 7388 7389 Level: developer 7390 7391 Note: The indices could be local or global, depending on the value of 'off'. 7392 */ 7393 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7394 { 7395 PetscInt dof; /* The number of unknowns on this point */ 7396 PetscInt cdof; /* The number of constraints on this point */ 7397 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7398 PetscInt cind = 0, k; 7399 7400 PetscFunctionBegin; 7401 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7402 PetscCall(PetscSectionGetDof(section, point, &dof)); 7403 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7404 if (!cdof || setBC) { 7405 for (k = 0; k < dof; ++k) { 7406 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7407 const PetscInt ind = indperm ? indperm[preind] : preind; 7408 7409 indices[ind] = off + k; 7410 } 7411 } else { 7412 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7413 for (k = 0; k < dof; ++k) { 7414 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7415 const PetscInt ind = indperm ? indperm[preind] : preind; 7416 7417 if ((cind < cdof) && (k == cdofs[cind])) { 7418 /* Insert check for returning constrained indices */ 7419 indices[ind] = -(off + k + 1); 7420 ++cind; 7421 } else { 7422 indices[ind] = off + k - (islocal ? 0 : cind); 7423 } 7424 } 7425 } 7426 *loff += dof; 7427 PetscFunctionReturn(PETSC_SUCCESS); 7428 } 7429 7430 /* 7431 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7432 7433 Input Parameters: 7434 + section - a section (global or local) 7435 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7436 . point - point within section 7437 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7438 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7439 . setBC - identify constrained (boundary condition) points via involution. 7440 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7441 . permsoff - offset 7442 - indperm - index permutation 7443 7444 Output Parameter: 7445 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7446 . indices - array to hold indices (as defined by section) of each dof associated with point 7447 7448 Notes: 7449 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7450 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7451 in the local vector. 7452 7453 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7454 significant). It is invalid to call with a global section and setBC=true. 7455 7456 Developer Note: 7457 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7458 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7459 offset could be obtained from the section instead of passing it explicitly as we do now. 7460 7461 Example: 7462 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7463 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7464 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7465 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. 7466 7467 Level: developer 7468 */ 7469 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[]) 7470 { 7471 PetscInt numFields, foff, f; 7472 7473 PetscFunctionBegin; 7474 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7475 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7476 for (f = 0, foff = 0; f < numFields; ++f) { 7477 PetscInt fdof, cfdof; 7478 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7479 PetscInt cind = 0, b; 7480 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7481 7482 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7483 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7484 if (!cfdof || setBC) { 7485 for (b = 0; b < fdof; ++b) { 7486 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7487 const PetscInt ind = indperm ? indperm[preind] : preind; 7488 7489 indices[ind] = off + foff + b; 7490 } 7491 } else { 7492 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7493 for (b = 0; b < fdof; ++b) { 7494 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7495 const PetscInt ind = indperm ? indperm[preind] : preind; 7496 7497 if ((cind < cfdof) && (b == fcdofs[cind])) { 7498 indices[ind] = -(off + foff + b + 1); 7499 ++cind; 7500 } else { 7501 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7502 } 7503 } 7504 } 7505 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7506 foffs[f] += fdof; 7507 } 7508 PetscFunctionReturn(PETSC_SUCCESS); 7509 } 7510 7511 /* 7512 This version believes the globalSection offsets for each field, rather than just the point offset 7513 7514 . foffs - The offset into 'indices' for each field, since it is segregated by field 7515 7516 Notes: 7517 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7518 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7519 */ 7520 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7521 { 7522 PetscInt numFields, foff, f; 7523 7524 PetscFunctionBegin; 7525 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7526 for (f = 0; f < numFields; ++f) { 7527 PetscInt fdof, cfdof; 7528 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7529 PetscInt cind = 0, b; 7530 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7531 7532 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7533 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7534 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7535 if (!cfdof) { 7536 for (b = 0; b < fdof; ++b) { 7537 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7538 const PetscInt ind = indperm ? indperm[preind] : preind; 7539 7540 indices[ind] = foff + b; 7541 } 7542 } else { 7543 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7544 for (b = 0; b < fdof; ++b) { 7545 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7546 const PetscInt ind = indperm ? indperm[preind] : preind; 7547 7548 if ((cind < cfdof) && (b == fcdofs[cind])) { 7549 indices[ind] = -(foff + b + 1); 7550 ++cind; 7551 } else { 7552 indices[ind] = foff + b - cind; 7553 } 7554 } 7555 } 7556 foffs[f] += fdof; 7557 } 7558 PetscFunctionReturn(PETSC_SUCCESS); 7559 } 7560 7561 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7562 { 7563 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7564 7565 PetscFunctionBegin; 7566 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7567 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7568 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7569 for (PetscInt p = 0; p < nPoints; p++) { 7570 PetscInt b = pnts[2 * p]; 7571 PetscInt bSecDof = 0, bOff; 7572 PetscInt cSecDof = 0; 7573 PetscSection indices_section; 7574 7575 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7576 if (!bSecDof) continue; 7577 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7578 indices_section = cSecDof > 0 ? cSec : section; 7579 if (numFields) { 7580 PetscInt fStart[32], fEnd[32]; 7581 7582 fStart[0] = 0; 7583 fEnd[0] = 0; 7584 for (PetscInt f = 0; f < numFields; f++) { 7585 PetscInt fDof = 0; 7586 7587 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7588 fStart[f + 1] = fStart[f] + fDof; 7589 fEnd[f + 1] = fStart[f + 1]; 7590 } 7591 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7592 // only apply permutations on one side 7593 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7594 for (PetscInt f = 0; f < numFields; f++) { 7595 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7596 } 7597 } else { 7598 PetscInt bEnd = 0; 7599 7600 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7601 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7602 7603 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7604 } 7605 } 7606 PetscFunctionReturn(PETSC_SUCCESS); 7607 } 7608 7609 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[]) 7610 { 7611 Mat cMat; 7612 PetscSection aSec, cSec; 7613 IS aIS; 7614 PetscInt aStart = -1, aEnd = -1; 7615 PetscInt sStart = -1, sEnd = -1; 7616 PetscInt cStart = -1, cEnd = -1; 7617 const PetscInt *anchors; 7618 PetscInt numFields, p; 7619 PetscInt newNumPoints = 0, newNumIndices = 0; 7620 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7621 PetscInt oldOffsets[32]; 7622 PetscInt newOffsets[32]; 7623 PetscInt oldOffsetsCopy[32]; 7624 PetscInt newOffsetsCopy[32]; 7625 PetscScalar *modMat = NULL; 7626 PetscBool anyConstrained = PETSC_FALSE; 7627 7628 PetscFunctionBegin; 7629 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7630 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7631 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7632 7633 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7634 /* if there are point-to-point constraints */ 7635 if (aSec) { 7636 PetscCall(PetscArrayzero(newOffsets, 32)); 7637 PetscCall(PetscArrayzero(oldOffsets, 32)); 7638 PetscCall(ISGetIndices(aIS, &anchors)); 7639 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7640 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7641 /* figure out how many points are going to be in the new element matrix 7642 * (we allow double counting, because it's all just going to be summed 7643 * into the global matrix anyway) */ 7644 for (p = 0; p < 2 * numPoints; p += 2) { 7645 PetscInt b = points[p]; 7646 PetscInt bDof = 0, bSecDof = 0; 7647 7648 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7649 if (!bSecDof) continue; 7650 7651 for (PetscInt f = 0; f < numFields; f++) { 7652 PetscInt fDof = 0; 7653 7654 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7655 oldOffsets[f + 1] += fDof; 7656 } 7657 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7658 if (bDof) { 7659 /* this point is constrained */ 7660 /* it is going to be replaced by its anchors */ 7661 PetscInt bOff, q; 7662 7663 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7664 for (q = 0; q < bDof; q++) { 7665 PetscInt a = anchors[bOff + q]; 7666 PetscInt aDof = 0; 7667 7668 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7669 if (aDof) { 7670 anyConstrained = PETSC_TRUE; 7671 newNumPoints += 1; 7672 } 7673 newNumIndices += aDof; 7674 for (PetscInt f = 0; f < numFields; ++f) { 7675 PetscInt fDof = 0; 7676 7677 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7678 newOffsets[f + 1] += fDof; 7679 } 7680 } 7681 } else { 7682 /* this point is not constrained */ 7683 newNumPoints++; 7684 newNumIndices += bSecDof; 7685 for (PetscInt f = 0; f < numFields; ++f) { 7686 PetscInt fDof; 7687 7688 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7689 newOffsets[f + 1] += fDof; 7690 } 7691 } 7692 } 7693 } 7694 if (!anyConstrained) { 7695 if (outNumPoints) *outNumPoints = 0; 7696 if (outNumIndices) *outNumIndices = 0; 7697 if (outPoints) *outPoints = NULL; 7698 if (outMat) *outMat = NULL; 7699 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7700 PetscFunctionReturn(PETSC_SUCCESS); 7701 } 7702 7703 if (outNumPoints) *outNumPoints = newNumPoints; 7704 if (outNumIndices) *outNumIndices = newNumIndices; 7705 7706 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7707 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7708 7709 if (!outPoints && !outMat) { 7710 if (offsets) { 7711 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7712 } 7713 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7714 PetscFunctionReturn(PETSC_SUCCESS); 7715 } 7716 7717 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7718 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7719 7720 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7721 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7722 7723 /* output arrays */ 7724 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7725 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7726 7727 // get the new Points 7728 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7729 PetscInt b = points[2 * p]; 7730 PetscInt bDof = 0, bSecDof = 0, bOff; 7731 7732 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7733 if (!bSecDof) continue; 7734 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7735 if (bDof) { 7736 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7737 for (PetscInt q = 0; q < bDof; q++) { 7738 PetscInt a = anchors[bOff + q], aDof = 0; 7739 7740 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7741 if (aDof) { 7742 newPoints[2 * newP] = a; 7743 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7744 newP++; 7745 } 7746 } 7747 } else { 7748 newPoints[2 * newP] = b; 7749 newPoints[2 * newP + 1] = points[2 * p + 1]; 7750 newP++; 7751 } 7752 } 7753 7754 if (outMat) { 7755 PetscScalar *tmpMat; 7756 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7757 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7758 7759 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7760 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7761 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7762 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7763 7764 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7765 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7766 7767 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7768 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7769 7770 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7771 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7772 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7773 // for each field, insert the anchor modification into modMat 7774 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7775 PetscInt fStart = oldOffsets[f]; 7776 PetscInt fNewStart = newOffsets[f]; 7777 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7778 PetscInt b = points[2 * p]; 7779 PetscInt bDof = 0, bSecDof = 0, bOff; 7780 7781 if (b >= sStart && b < sEnd) { 7782 if (numFields) { 7783 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7784 } else { 7785 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7786 } 7787 } 7788 if (!bSecDof) continue; 7789 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7790 if (bDof) { 7791 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7792 for (PetscInt q = 0; q < bDof; q++, newP++) { 7793 PetscInt a = anchors[bOff + q], aDof = 0; 7794 7795 if (a >= sStart && a < sEnd) { 7796 if (numFields) { 7797 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7798 } else { 7799 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7800 } 7801 } 7802 if (aDof) { 7803 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7804 for (PetscInt d = 0; d < bSecDof; d++) { 7805 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7806 } 7807 } 7808 oNew += aDof; 7809 } 7810 } else { 7811 // Insert the identity matrix in this block 7812 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7813 oNew += bSecDof; 7814 newP++; 7815 } 7816 o += bSecDof; 7817 } 7818 } 7819 7820 *outMat = modMat; 7821 7822 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7823 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7824 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7825 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7826 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7827 } 7828 PetscCall(ISRestoreIndices(aIS, &anchors)); 7829 7830 /* output */ 7831 if (outPoints) { 7832 *outPoints = newPoints; 7833 } else { 7834 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7835 } 7836 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7837 PetscFunctionReturn(PETSC_SUCCESS); 7838 } 7839 7840 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) 7841 { 7842 PetscScalar *modMat = NULL; 7843 PetscInt newNumIndices = -1; 7844 7845 PetscFunctionBegin; 7846 /* 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. 7847 modMat is that matrix C */ 7848 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7849 if (outNumIndices) *outNumIndices = newNumIndices; 7850 if (modMat) { 7851 const PetscScalar *newValues = values; 7852 7853 if (multiplyRight) { 7854 PetscScalar *newNewValues = NULL; 7855 PetscBLASInt M = newNumIndices; 7856 PetscBLASInt N = numRows; 7857 PetscBLASInt K = numIndices; 7858 PetscScalar a = 1.0, b = 0.0; 7859 7860 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); 7861 7862 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7863 // row-major to column-major conversion, right multiplication becomes left multiplication 7864 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7865 7866 numCols = newNumIndices; 7867 newValues = newNewValues; 7868 } 7869 7870 if (multiplyLeft) { 7871 PetscScalar *newNewValues = NULL; 7872 PetscBLASInt M = numCols; 7873 PetscBLASInt N = newNumIndices; 7874 PetscBLASInt K = numIndices; 7875 PetscScalar a = 1.0, b = 0.0; 7876 7877 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); 7878 7879 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7880 // row-major to column-major conversion, left multiplication becomes right multiplication 7881 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7882 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7883 newValues = newNewValues; 7884 } 7885 *outValues = (PetscScalar *)newValues; 7886 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7887 } 7888 PetscFunctionReturn(PETSC_SUCCESS); 7889 } 7890 7891 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) 7892 { 7893 PetscFunctionBegin; 7894 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7895 PetscFunctionReturn(PETSC_SUCCESS); 7896 } 7897 7898 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7899 { 7900 /* Closure ordering */ 7901 PetscSection clSection; 7902 IS clPoints; 7903 const PetscInt *clp; 7904 PetscInt *points; 7905 PetscInt Ncl, Ni = 0; 7906 7907 PetscFunctionBeginHot; 7908 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7909 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7910 PetscInt dof; 7911 7912 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7913 Ni += dof; 7914 } 7915 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7916 *closureSize = Ni; 7917 PetscFunctionReturn(PETSC_SUCCESS); 7918 } 7919 7920 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) 7921 { 7922 /* Closure ordering */ 7923 PetscSection clSection; 7924 IS clPoints; 7925 const PetscInt *clp; 7926 PetscInt *points; 7927 const PetscInt *clperm = NULL; 7928 /* Dof permutation and sign flips */ 7929 const PetscInt **perms[32] = {NULL}; 7930 const PetscScalar **flips[32] = {NULL}; 7931 PetscScalar *valCopy = NULL; 7932 /* Hanging node constraints */ 7933 PetscInt *pointsC = NULL; 7934 PetscScalar *valuesC = NULL; 7935 PetscInt NclC, NiC; 7936 7937 PetscInt *idx; 7938 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7939 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7940 PetscInt idxStart, idxEnd; 7941 PetscInt nRows, nCols; 7942 7943 PetscFunctionBeginHot; 7944 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7945 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7946 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7947 PetscAssertPointer(numRows, 6); 7948 PetscAssertPointer(numCols, 7); 7949 if (indices) PetscAssertPointer(indices, 8); 7950 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7951 if (values) PetscAssertPointer(values, 10); 7952 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7953 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7954 PetscCall(PetscArrayzero(offsets, 32)); 7955 /* 1) Get points in closure */ 7956 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7957 if (useClPerm) { 7958 PetscInt depth, clsize; 7959 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7960 for (clsize = 0, p = 0; p < Ncl; p++) { 7961 PetscInt dof; 7962 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7963 clsize += dof; 7964 } 7965 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7966 } 7967 /* 2) Get number of indices on these points and field offsets from section */ 7968 for (p = 0; p < Ncl * 2; p += 2) { 7969 PetscInt dof, fdof; 7970 7971 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7972 for (f = 0; f < Nf; ++f) { 7973 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7974 offsets[f + 1] += fdof; 7975 } 7976 Ni += dof; 7977 } 7978 if (*numRows == -1) *numRows = Ni; 7979 if (*numCols == -1) *numCols = Ni; 7980 nRows = *numRows; 7981 nCols = *numCols; 7982 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7983 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7984 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7985 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 7986 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 7987 for (f = 0; f < PetscMax(1, Nf); ++f) { 7988 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7989 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7990 /* may need to apply sign changes to the element matrix */ 7991 if (values && flips[f]) { 7992 PetscInt foffset = offsets[f]; 7993 7994 for (p = 0; p < Ncl; ++p) { 7995 PetscInt pnt = points[2 * p], fdof; 7996 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7997 7998 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7999 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8000 if (flip) { 8001 PetscInt i, j, k; 8002 8003 if (!valCopy) { 8004 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8005 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8006 *values = valCopy; 8007 } 8008 for (i = 0; i < fdof; ++i) { 8009 PetscScalar fval = flip[i]; 8010 8011 if (multiplyRight) { 8012 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8013 } 8014 if (multiplyLeft) { 8015 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8016 } 8017 } 8018 } 8019 foffset += fdof; 8020 } 8021 } 8022 } 8023 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8024 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8025 if (NclC) { 8026 if (multiplyRight) { *numCols = nCols = NiC; } 8027 if (multiplyLeft) { *numRows = nRows = NiC; } 8028 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8029 for (f = 0; f < PetscMax(1, Nf); ++f) { 8030 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8031 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8032 } 8033 for (f = 0; f < PetscMax(1, Nf); ++f) { 8034 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8035 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8036 } 8037 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8038 Ncl = NclC; 8039 Ni = NiC; 8040 points = pointsC; 8041 if (values) *values = valuesC; 8042 } 8043 /* 5) Calculate indices */ 8044 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8045 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8046 if (Nf) { 8047 PetscInt idxOff; 8048 PetscBool useFieldOffsets; 8049 8050 if (outOffsets) { 8051 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8052 } 8053 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8054 if (useFieldOffsets) { 8055 for (p = 0; p < Ncl; ++p) { 8056 const PetscInt pnt = points[p * 2]; 8057 8058 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8059 } 8060 } else { 8061 for (p = 0; p < Ncl; ++p) { 8062 const PetscInt pnt = points[p * 2]; 8063 8064 if (pnt < idxStart || pnt >= idxEnd) continue; 8065 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8066 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8067 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8068 * global section. */ 8069 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8070 } 8071 } 8072 } else { 8073 PetscInt off = 0, idxOff; 8074 8075 for (p = 0; p < Ncl; ++p) { 8076 const PetscInt pnt = points[p * 2]; 8077 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8078 8079 if (pnt < idxStart || pnt >= idxEnd) continue; 8080 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8081 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8082 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8083 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8084 } 8085 } 8086 /* 6) Cleanup */ 8087 for (f = 0; f < PetscMax(1, Nf); ++f) { 8088 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8089 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8090 } 8091 if (NclC) { 8092 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8093 } else { 8094 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8095 } 8096 8097 if (indices) *indices = idx; 8098 PetscFunctionReturn(PETSC_SUCCESS); 8099 } 8100 8101 /*@C 8102 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8103 8104 Not collective 8105 8106 Input Parameters: 8107 + dm - The `DM` 8108 . section - The `PetscSection` describing the points (a local section) 8109 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8110 . point - The point defining the closure 8111 - useClPerm - Use the closure point permutation if available 8112 8113 Output Parameters: 8114 + numIndices - The number of dof indices in the closure of point with the input sections 8115 . indices - The dof indices 8116 . outOffsets - Array to write the field offsets into, or `NULL` 8117 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8118 8119 Level: advanced 8120 8121 Notes: 8122 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8123 8124 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8125 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8126 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8127 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8128 indices (with the above semantics) are implied. 8129 8130 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8131 `PetscSection`, `DMGetGlobalSection()` 8132 @*/ 8133 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8134 { 8135 PetscInt numRows = -1, numCols = -1; 8136 8137 PetscFunctionBeginHot; 8138 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8139 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8140 *numIndices = numRows; 8141 PetscFunctionReturn(PETSC_SUCCESS); 8142 } 8143 8144 /*@C 8145 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8146 8147 Not collective 8148 8149 Input Parameters: 8150 + dm - The `DM` 8151 . section - The `PetscSection` describing the points (a local section) 8152 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8153 . point - The point defining the closure 8154 - useClPerm - Use the closure point permutation if available 8155 8156 Output Parameters: 8157 + numIndices - The number of dof indices in the closure of point with the input sections 8158 . indices - The dof indices 8159 . outOffsets - Array to write the field offsets into, or `NULL` 8160 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8161 8162 Level: advanced 8163 8164 Notes: 8165 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8166 8167 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8168 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8169 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8170 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8171 indices (with the above semantics) are implied. 8172 8173 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8174 @*/ 8175 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8176 { 8177 PetscFunctionBegin; 8178 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8179 PetscAssertPointer(indices, 7); 8180 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8181 PetscFunctionReturn(PETSC_SUCCESS); 8182 } 8183 8184 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8185 { 8186 DM_Plex *mesh = (DM_Plex *)dm->data; 8187 PetscInt *indices; 8188 PetscInt numIndices; 8189 const PetscScalar *valuesOrig = values; 8190 PetscErrorCode ierr; 8191 8192 PetscFunctionBegin; 8193 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8194 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8195 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8196 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8197 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8198 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8199 8200 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8201 8202 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8203 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8204 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8205 if (ierr) { 8206 PetscMPIInt rank; 8207 8208 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8209 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8210 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8211 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8212 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8213 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8214 } 8215 if (mesh->printFEM > 1) { 8216 PetscInt i; 8217 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8218 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8219 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8220 } 8221 8222 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8223 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8224 PetscFunctionReturn(PETSC_SUCCESS); 8225 } 8226 8227 /*@C 8228 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8229 8230 Not collective 8231 8232 Input Parameters: 8233 + dm - The `DM` 8234 . section - The section describing the layout in `v`, or `NULL` to use the default section 8235 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8236 . A - The matrix 8237 . point - The point in the `DM` 8238 . values - The array of values 8239 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8240 8241 Level: intermediate 8242 8243 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8244 @*/ 8245 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8246 { 8247 PetscFunctionBegin; 8248 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8249 PetscFunctionReturn(PETSC_SUCCESS); 8250 } 8251 8252 /*@C 8253 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8254 8255 Not collective 8256 8257 Input Parameters: 8258 + dmRow - The `DM` for the row fields 8259 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8260 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8261 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8262 . dmCol - The `DM` for the column fields 8263 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8264 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8265 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8266 . A - The matrix 8267 . point - The point in the `DM` 8268 . values - The array of values 8269 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8270 8271 Level: intermediate 8272 8273 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8274 @*/ 8275 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) 8276 { 8277 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8278 PetscInt *indicesRow, *indicesCol; 8279 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8280 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8281 8282 PetscErrorCode ierr; 8283 8284 PetscFunctionBegin; 8285 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8286 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8287 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8288 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8289 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8290 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8291 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8292 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8293 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8294 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8295 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8296 8297 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8298 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8299 valuesV1 = valuesV0; 8300 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8301 valuesV2 = valuesV1; 8302 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8303 8304 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8305 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8306 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8307 if (ierr) { 8308 PetscMPIInt rank; 8309 8310 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8311 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8312 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8313 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8314 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8315 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8316 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8317 } 8318 8319 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8320 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8321 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8322 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8323 PetscFunctionReturn(PETSC_SUCCESS); 8324 } 8325 8326 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8327 { 8328 DM_Plex *mesh = (DM_Plex *)dmf->data; 8329 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8330 PetscInt *cpoints = NULL; 8331 PetscInt *findices, *cindices; 8332 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8333 PetscInt foffsets[32], coffsets[32]; 8334 DMPolytopeType ct; 8335 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8336 PetscErrorCode ierr; 8337 8338 PetscFunctionBegin; 8339 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8340 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8341 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8342 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8343 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8344 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8345 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8346 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8347 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8348 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8349 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8350 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8351 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8352 PetscCall(PetscArrayzero(foffsets, 32)); 8353 PetscCall(PetscArrayzero(coffsets, 32)); 8354 /* Column indices */ 8355 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8356 maxFPoints = numCPoints; 8357 /* Compress out points not in the section */ 8358 /* TODO: Squeeze out points with 0 dof as well */ 8359 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8360 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8361 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8362 cpoints[q * 2] = cpoints[p]; 8363 cpoints[q * 2 + 1] = cpoints[p + 1]; 8364 ++q; 8365 } 8366 } 8367 numCPoints = q; 8368 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8369 PetscInt fdof; 8370 8371 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8372 if (!dof) continue; 8373 for (f = 0; f < numFields; ++f) { 8374 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8375 coffsets[f + 1] += fdof; 8376 } 8377 numCIndices += dof; 8378 } 8379 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8380 /* Row indices */ 8381 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8382 { 8383 DMPlexTransform tr; 8384 DMPolytopeType *rct; 8385 PetscInt *rsize, *rcone, *rornt, Nt; 8386 8387 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8388 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8389 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8390 numSubcells = rsize[Nt - 1]; 8391 PetscCall(DMPlexTransformDestroy(&tr)); 8392 } 8393 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8394 for (r = 0, q = 0; r < numSubcells; ++r) { 8395 /* TODO Map from coarse to fine cells */ 8396 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8397 /* Compress out points not in the section */ 8398 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8399 for (p = 0; p < numFPoints * 2; p += 2) { 8400 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8401 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8402 if (!dof) continue; 8403 for (s = 0; s < q; ++s) 8404 if (fpoints[p] == ftotpoints[s * 2]) break; 8405 if (s < q) continue; 8406 ftotpoints[q * 2] = fpoints[p]; 8407 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8408 ++q; 8409 } 8410 } 8411 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8412 } 8413 numFPoints = q; 8414 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8415 PetscInt fdof; 8416 8417 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8418 if (!dof) continue; 8419 for (f = 0; f < numFields; ++f) { 8420 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8421 foffsets[f + 1] += fdof; 8422 } 8423 numFIndices += dof; 8424 } 8425 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8426 8427 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8428 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8429 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8430 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8431 if (numFields) { 8432 const PetscInt **permsF[32] = {NULL}; 8433 const PetscInt **permsC[32] = {NULL}; 8434 8435 for (f = 0; f < numFields; f++) { 8436 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8437 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8438 } 8439 for (p = 0; p < numFPoints; p++) { 8440 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8441 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8442 } 8443 for (p = 0; p < numCPoints; p++) { 8444 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8445 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8446 } 8447 for (f = 0; f < numFields; f++) { 8448 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8449 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8450 } 8451 } else { 8452 const PetscInt **permsF = NULL; 8453 const PetscInt **permsC = NULL; 8454 8455 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8456 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8457 for (p = 0, off = 0; p < numFPoints; p++) { 8458 const PetscInt *perm = permsF ? permsF[p] : NULL; 8459 8460 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8461 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8462 } 8463 for (p = 0, off = 0; p < numCPoints; p++) { 8464 const PetscInt *perm = permsC ? permsC[p] : NULL; 8465 8466 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8467 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8468 } 8469 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8470 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8471 } 8472 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8473 /* TODO: flips */ 8474 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8475 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8476 if (ierr) { 8477 PetscMPIInt rank; 8478 8479 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8480 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8481 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8482 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8483 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8484 } 8485 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8486 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8487 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8488 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8489 PetscFunctionReturn(PETSC_SUCCESS); 8490 } 8491 8492 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8493 { 8494 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8495 PetscInt *cpoints = NULL; 8496 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8497 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8498 DMPolytopeType ct; 8499 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8500 8501 PetscFunctionBegin; 8502 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8503 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8504 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8505 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8506 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8507 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8508 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8509 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8510 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8511 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8512 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8513 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8514 /* Column indices */ 8515 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8516 maxFPoints = numCPoints; 8517 /* Compress out points not in the section */ 8518 /* TODO: Squeeze out points with 0 dof as well */ 8519 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8520 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8521 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8522 cpoints[q * 2] = cpoints[p]; 8523 cpoints[q * 2 + 1] = cpoints[p + 1]; 8524 ++q; 8525 } 8526 } 8527 numCPoints = q; 8528 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8529 PetscInt fdof; 8530 8531 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8532 if (!dof) continue; 8533 for (f = 0; f < numFields; ++f) { 8534 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8535 coffsets[f + 1] += fdof; 8536 } 8537 numCIndices += dof; 8538 } 8539 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8540 /* Row indices */ 8541 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8542 { 8543 DMPlexTransform tr; 8544 DMPolytopeType *rct; 8545 PetscInt *rsize, *rcone, *rornt, Nt; 8546 8547 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8548 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8549 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8550 numSubcells = rsize[Nt - 1]; 8551 PetscCall(DMPlexTransformDestroy(&tr)); 8552 } 8553 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8554 for (r = 0, q = 0; r < numSubcells; ++r) { 8555 /* TODO Map from coarse to fine cells */ 8556 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8557 /* Compress out points not in the section */ 8558 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8559 for (p = 0; p < numFPoints * 2; p += 2) { 8560 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8561 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8562 if (!dof) continue; 8563 for (s = 0; s < q; ++s) 8564 if (fpoints[p] == ftotpoints[s * 2]) break; 8565 if (s < q) continue; 8566 ftotpoints[q * 2] = fpoints[p]; 8567 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8568 ++q; 8569 } 8570 } 8571 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8572 } 8573 numFPoints = q; 8574 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8575 PetscInt fdof; 8576 8577 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8578 if (!dof) continue; 8579 for (f = 0; f < numFields; ++f) { 8580 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8581 foffsets[f + 1] += fdof; 8582 } 8583 numFIndices += dof; 8584 } 8585 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8586 8587 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8588 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8589 if (numFields) { 8590 const PetscInt **permsF[32] = {NULL}; 8591 const PetscInt **permsC[32] = {NULL}; 8592 8593 for (f = 0; f < numFields; f++) { 8594 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8595 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8596 } 8597 for (p = 0; p < numFPoints; p++) { 8598 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8599 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8600 } 8601 for (p = 0; p < numCPoints; p++) { 8602 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8603 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8604 } 8605 for (f = 0; f < numFields; f++) { 8606 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8607 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8608 } 8609 } else { 8610 const PetscInt **permsF = NULL; 8611 const PetscInt **permsC = NULL; 8612 8613 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8614 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8615 for (p = 0, off = 0; p < numFPoints; p++) { 8616 const PetscInt *perm = permsF ? permsF[p] : NULL; 8617 8618 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8619 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8620 } 8621 for (p = 0, off = 0; p < numCPoints; p++) { 8622 const PetscInt *perm = permsC ? permsC[p] : NULL; 8623 8624 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8625 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8626 } 8627 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8628 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8629 } 8630 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8631 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8632 PetscFunctionReturn(PETSC_SUCCESS); 8633 } 8634 8635 /*@ 8636 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8637 8638 Input Parameter: 8639 . dm - The `DMPLEX` object 8640 8641 Output Parameter: 8642 . cellHeight - The height of a cell 8643 8644 Level: developer 8645 8646 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8647 @*/ 8648 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8649 { 8650 DM_Plex *mesh = (DM_Plex *)dm->data; 8651 8652 PetscFunctionBegin; 8653 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8654 PetscAssertPointer(cellHeight, 2); 8655 *cellHeight = mesh->vtkCellHeight; 8656 PetscFunctionReturn(PETSC_SUCCESS); 8657 } 8658 8659 /*@ 8660 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8661 8662 Input Parameters: 8663 + dm - The `DMPLEX` object 8664 - cellHeight - The height of a cell 8665 8666 Level: developer 8667 8668 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8669 @*/ 8670 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8671 { 8672 DM_Plex *mesh = (DM_Plex *)dm->data; 8673 8674 PetscFunctionBegin; 8675 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8676 mesh->vtkCellHeight = cellHeight; 8677 PetscFunctionReturn(PETSC_SUCCESS); 8678 } 8679 8680 /*@ 8681 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8682 8683 Input Parameters: 8684 + dm - The `DMPLEX` object 8685 - ct - The `DMPolytopeType` of the cell 8686 8687 Output Parameters: 8688 + start - The first cell of this type, or `NULL` 8689 - end - The upper bound on this celltype, or `NULL` 8690 8691 Level: advanced 8692 8693 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8694 @*/ 8695 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8696 { 8697 DM_Plex *mesh = (DM_Plex *)dm->data; 8698 DMLabel label; 8699 PetscInt pStart, pEnd; 8700 8701 PetscFunctionBegin; 8702 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8703 if (start) { 8704 PetscAssertPointer(start, 3); 8705 *start = 0; 8706 } 8707 if (end) { 8708 PetscAssertPointer(end, 4); 8709 *end = 0; 8710 } 8711 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8712 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8713 if (mesh->tr) { 8714 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8715 } else { 8716 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8717 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8718 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8719 } 8720 PetscFunctionReturn(PETSC_SUCCESS); 8721 } 8722 8723 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8724 { 8725 PetscSection section, globalSection; 8726 PetscInt *numbers, p; 8727 8728 PetscFunctionBegin; 8729 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8730 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8731 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8732 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8733 PetscCall(PetscSectionSetUp(section)); 8734 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8735 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8736 for (p = pStart; p < pEnd; ++p) { 8737 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8738 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8739 else numbers[p - pStart] += shift; 8740 } 8741 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8742 if (globalSize) { 8743 PetscLayout layout; 8744 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8745 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8746 PetscCall(PetscLayoutDestroy(&layout)); 8747 } 8748 PetscCall(PetscSectionDestroy(§ion)); 8749 PetscCall(PetscSectionDestroy(&globalSection)); 8750 PetscFunctionReturn(PETSC_SUCCESS); 8751 } 8752 8753 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8754 { 8755 PetscInt cellHeight, cStart, cEnd; 8756 8757 PetscFunctionBegin; 8758 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8759 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8760 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8761 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8762 PetscFunctionReturn(PETSC_SUCCESS); 8763 } 8764 8765 /*@ 8766 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8767 8768 Input Parameter: 8769 . dm - The `DMPLEX` object 8770 8771 Output Parameter: 8772 . globalCellNumbers - Global cell numbers for all cells on this process 8773 8774 Level: developer 8775 8776 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8777 @*/ 8778 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8779 { 8780 DM_Plex *mesh = (DM_Plex *)dm->data; 8781 8782 PetscFunctionBegin; 8783 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8784 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8785 *globalCellNumbers = mesh->globalCellNumbers; 8786 PetscFunctionReturn(PETSC_SUCCESS); 8787 } 8788 8789 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8790 { 8791 PetscInt vStart, vEnd; 8792 8793 PetscFunctionBegin; 8794 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8795 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8796 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8797 PetscFunctionReturn(PETSC_SUCCESS); 8798 } 8799 8800 /*@ 8801 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8802 8803 Input Parameter: 8804 . dm - The `DMPLEX` object 8805 8806 Output Parameter: 8807 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8808 8809 Level: developer 8810 8811 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8812 @*/ 8813 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8814 { 8815 DM_Plex *mesh = (DM_Plex *)dm->data; 8816 8817 PetscFunctionBegin; 8818 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8819 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8820 *globalVertexNumbers = mesh->globalVertexNumbers; 8821 PetscFunctionReturn(PETSC_SUCCESS); 8822 } 8823 8824 /*@ 8825 DMPlexCreatePointNumbering - Create a global numbering for all points. 8826 8827 Collective 8828 8829 Input Parameter: 8830 . dm - The `DMPLEX` object 8831 8832 Output Parameter: 8833 . globalPointNumbers - Global numbers for all points on this process 8834 8835 Level: developer 8836 8837 Notes: 8838 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8839 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8840 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8841 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8842 8843 The partitioned mesh is 8844 ``` 8845 (2)--0--(3)--1--(4) (1)--0--(2) 8846 ``` 8847 and its global numbering is 8848 ``` 8849 (3)--0--(4)--1--(5)--2--(6) 8850 ``` 8851 Then the global numbering is provided as 8852 ``` 8853 [0] Number of indices in set 5 8854 [0] 0 0 8855 [0] 1 1 8856 [0] 2 3 8857 [0] 3 4 8858 [0] 4 -6 8859 [1] Number of indices in set 3 8860 [1] 0 2 8861 [1] 1 5 8862 [1] 2 6 8863 ``` 8864 8865 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8866 @*/ 8867 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8868 { 8869 IS nums[4]; 8870 PetscInt depths[4], gdepths[4], starts[4]; 8871 PetscInt depth, d, shift = 0; 8872 PetscBool empty = PETSC_FALSE; 8873 8874 PetscFunctionBegin; 8875 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8876 PetscCall(DMPlexGetDepth(dm, &depth)); 8877 // For unstratified meshes use dim instead of depth 8878 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8879 // If any stratum is empty, we must mark all empty 8880 for (d = 0; d <= depth; ++d) { 8881 PetscInt end; 8882 8883 depths[d] = depth - d; 8884 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8885 if (!(starts[d] - end)) empty = PETSC_TRUE; 8886 } 8887 if (empty) 8888 for (d = 0; d <= depth; ++d) { 8889 depths[d] = -1; 8890 starts[d] = -1; 8891 } 8892 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8893 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8894 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]); 8895 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8896 for (d = 0; d <= depth; ++d) { 8897 PetscInt pStart, pEnd, gsize; 8898 8899 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8900 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8901 shift += gsize; 8902 } 8903 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8904 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8905 PetscFunctionReturn(PETSC_SUCCESS); 8906 } 8907 8908 /*@ 8909 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 8910 8911 Collective 8912 8913 Input Parameter: 8914 . dm - The `DMPLEX` object 8915 8916 Output Parameter: 8917 . globalEdgeNumbers - Global numbers for all edges on this process 8918 8919 Level: developer 8920 8921 Notes: 8922 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). 8923 8924 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 8925 @*/ 8926 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 8927 { 8928 PetscSF sf; 8929 PetscInt eStart, eEnd; 8930 8931 PetscFunctionBegin; 8932 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8933 PetscCall(DMGetPointSF(dm, &sf)); 8934 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8935 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 8936 PetscFunctionReturn(PETSC_SUCCESS); 8937 } 8938 8939 /*@ 8940 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8941 8942 Input Parameter: 8943 . dm - The `DMPLEX` object 8944 8945 Output Parameter: 8946 . ranks - The rank field 8947 8948 Options Database Key: 8949 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8950 8951 Level: intermediate 8952 8953 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8954 @*/ 8955 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8956 { 8957 DM rdm; 8958 PetscFE fe; 8959 PetscScalar *r; 8960 PetscMPIInt rank; 8961 DMPolytopeType ct; 8962 PetscInt dim, cStart, cEnd, c; 8963 PetscBool simplex; 8964 8965 PetscFunctionBeginUser; 8966 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8967 PetscAssertPointer(ranks, 2); 8968 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8969 PetscCall(DMClone(dm, &rdm)); 8970 PetscCall(DMGetDimension(rdm, &dim)); 8971 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8972 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8973 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8974 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8975 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8976 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8977 PetscCall(PetscFEDestroy(&fe)); 8978 PetscCall(DMCreateDS(rdm)); 8979 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8980 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8981 PetscCall(VecGetArray(*ranks, &r)); 8982 for (c = cStart; c < cEnd; ++c) { 8983 PetscScalar *lr; 8984 8985 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8986 if (lr) *lr = rank; 8987 } 8988 PetscCall(VecRestoreArray(*ranks, &r)); 8989 PetscCall(DMDestroy(&rdm)); 8990 PetscFunctionReturn(PETSC_SUCCESS); 8991 } 8992 8993 /*@ 8994 DMPlexCreateLabelField - Create a field whose value is the label value for that point 8995 8996 Input Parameters: 8997 + dm - The `DMPLEX` 8998 - label - The `DMLabel` 8999 9000 Output Parameter: 9001 . val - The label value field 9002 9003 Options Database Key: 9004 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9005 9006 Level: intermediate 9007 9008 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9009 @*/ 9010 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9011 { 9012 DM rdm, plex; 9013 Vec lval; 9014 PetscSection section; 9015 PetscFE fe; 9016 PetscScalar *v; 9017 PetscInt dim, pStart, pEnd, p, cStart; 9018 DMPolytopeType ct; 9019 char name[PETSC_MAX_PATH_LEN]; 9020 const char *lname, *prefix; 9021 9022 PetscFunctionBeginUser; 9023 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9024 PetscAssertPointer(label, 2); 9025 PetscAssertPointer(val, 3); 9026 PetscCall(DMClone(dm, &rdm)); 9027 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9028 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9029 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9030 PetscCall(DMDestroy(&plex)); 9031 PetscCall(DMGetDimension(rdm, &dim)); 9032 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9033 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9034 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9035 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9036 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9037 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9038 PetscCall(PetscFEDestroy(&fe)); 9039 PetscCall(DMCreateDS(rdm)); 9040 PetscCall(DMCreateGlobalVector(rdm, val)); 9041 PetscCall(DMCreateLocalVector(rdm, &lval)); 9042 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9043 PetscCall(DMGetLocalSection(rdm, §ion)); 9044 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9045 PetscCall(VecGetArray(lval, &v)); 9046 for (p = pStart; p < pEnd; ++p) { 9047 PetscInt cval, dof, off; 9048 9049 PetscCall(PetscSectionGetDof(section, p, &dof)); 9050 if (!dof) continue; 9051 PetscCall(DMLabelGetValue(label, p, &cval)); 9052 PetscCall(PetscSectionGetOffset(section, p, &off)); 9053 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9054 } 9055 PetscCall(VecRestoreArray(lval, &v)); 9056 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9057 PetscCall(VecDestroy(&lval)); 9058 PetscCall(DMDestroy(&rdm)); 9059 PetscFunctionReturn(PETSC_SUCCESS); 9060 } 9061 9062 /*@ 9063 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9064 9065 Input Parameter: 9066 . dm - The `DMPLEX` object 9067 9068 Level: developer 9069 9070 Notes: 9071 This is a useful diagnostic when creating meshes programmatically. 9072 9073 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9074 9075 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9076 @*/ 9077 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9078 { 9079 PetscSection coneSection, supportSection; 9080 const PetscInt *cone, *support; 9081 PetscInt coneSize, c, supportSize, s; 9082 PetscInt pStart, pEnd, p, pp, csize, ssize; 9083 PetscBool storagecheck = PETSC_TRUE; 9084 9085 PetscFunctionBegin; 9086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9087 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9088 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9089 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9090 /* Check that point p is found in the support of its cone points, and vice versa */ 9091 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9092 for (p = pStart; p < pEnd; ++p) { 9093 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9094 PetscCall(DMPlexGetCone(dm, p, &cone)); 9095 for (c = 0; c < coneSize; ++c) { 9096 PetscBool dup = PETSC_FALSE; 9097 PetscInt d; 9098 for (d = c - 1; d >= 0; --d) { 9099 if (cone[c] == cone[d]) { 9100 dup = PETSC_TRUE; 9101 break; 9102 } 9103 } 9104 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9105 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9106 for (s = 0; s < supportSize; ++s) { 9107 if (support[s] == p) break; 9108 } 9109 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9110 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9111 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9112 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9113 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9114 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9115 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9116 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]); 9117 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9118 } 9119 } 9120 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9121 if (p != pp) { 9122 storagecheck = PETSC_FALSE; 9123 continue; 9124 } 9125 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9126 PetscCall(DMPlexGetSupport(dm, p, &support)); 9127 for (s = 0; s < supportSize; ++s) { 9128 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9129 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9130 for (c = 0; c < coneSize; ++c) { 9131 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9132 if (cone[c] != pp) { 9133 c = 0; 9134 break; 9135 } 9136 if (cone[c] == p) break; 9137 } 9138 if (c >= coneSize) { 9139 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9140 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9141 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9142 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9143 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9144 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9145 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9146 } 9147 } 9148 } 9149 if (storagecheck) { 9150 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9151 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9152 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9153 } 9154 PetscFunctionReturn(PETSC_SUCCESS); 9155 } 9156 9157 /* 9158 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. 9159 */ 9160 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9161 { 9162 DMPolytopeType cct; 9163 PetscInt ptpoints[4]; 9164 const PetscInt *cone, *ccone, *ptcone; 9165 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9166 9167 PetscFunctionBegin; 9168 *unsplit = 0; 9169 switch (ct) { 9170 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9171 ptpoints[npt++] = c; 9172 break; 9173 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9174 PetscCall(DMPlexGetCone(dm, c, &cone)); 9175 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9176 for (cp = 0; cp < coneSize; ++cp) { 9177 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9178 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9179 } 9180 break; 9181 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9182 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9183 PetscCall(DMPlexGetCone(dm, c, &cone)); 9184 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9185 for (cp = 0; cp < coneSize; ++cp) { 9186 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9187 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9188 for (ccp = 0; ccp < cconeSize; ++ccp) { 9189 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9190 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9191 PetscInt p; 9192 for (p = 0; p < npt; ++p) 9193 if (ptpoints[p] == ccone[ccp]) break; 9194 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9195 } 9196 } 9197 } 9198 break; 9199 default: 9200 break; 9201 } 9202 for (pt = 0; pt < npt; ++pt) { 9203 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9204 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9205 } 9206 PetscFunctionReturn(PETSC_SUCCESS); 9207 } 9208 9209 /*@ 9210 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9211 9212 Input Parameters: 9213 + dm - The `DMPLEX` object 9214 - cellHeight - Normally 0 9215 9216 Level: developer 9217 9218 Notes: 9219 This is a useful diagnostic when creating meshes programmatically. 9220 Currently applicable only to homogeneous simplex or tensor meshes. 9221 9222 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9223 9224 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9225 @*/ 9226 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9227 { 9228 DMPlexInterpolatedFlag interp; 9229 DMPolytopeType ct; 9230 PetscInt vStart, vEnd, cStart, cEnd, c; 9231 9232 PetscFunctionBegin; 9233 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9234 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9235 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9236 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9237 for (c = cStart; c < cEnd; ++c) { 9238 PetscInt *closure = NULL; 9239 PetscInt coneSize, closureSize, cl, Nv = 0; 9240 9241 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9242 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9243 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9244 if (interp == DMPLEX_INTERPOLATED_FULL) { 9245 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9246 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)); 9247 } 9248 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9249 for (cl = 0; cl < closureSize * 2; cl += 2) { 9250 const PetscInt p = closure[cl]; 9251 if ((p >= vStart) && (p < vEnd)) ++Nv; 9252 } 9253 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9254 /* Special Case: Tensor faces with identified vertices */ 9255 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9256 PetscInt unsplit; 9257 9258 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9259 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9260 } 9261 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)); 9262 } 9263 PetscFunctionReturn(PETSC_SUCCESS); 9264 } 9265 9266 /*@ 9267 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9268 9269 Collective 9270 9271 Input Parameters: 9272 + dm - The `DMPLEX` object 9273 - cellHeight - Normally 0 9274 9275 Level: developer 9276 9277 Notes: 9278 This is a useful diagnostic when creating meshes programmatically. 9279 This routine is only relevant for meshes that are fully interpolated across all ranks. 9280 It will error out if a partially interpolated mesh is given on some rank. 9281 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9282 9283 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9284 9285 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9286 @*/ 9287 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9288 { 9289 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9290 DMPlexInterpolatedFlag interpEnum; 9291 9292 PetscFunctionBegin; 9293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9294 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9295 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9296 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9297 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9298 PetscFunctionReturn(PETSC_SUCCESS); 9299 } 9300 9301 PetscCall(DMGetDimension(dm, &dim)); 9302 PetscCall(DMPlexGetDepth(dm, &depth)); 9303 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9304 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9305 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9306 for (c = cStart; c < cEnd; ++c) { 9307 const PetscInt *cone, *ornt, *faceSizes, *faces; 9308 const DMPolytopeType *faceTypes; 9309 DMPolytopeType ct; 9310 PetscInt numFaces, coneSize, f; 9311 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9312 9313 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9314 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9315 if (unsplit) continue; 9316 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9317 PetscCall(DMPlexGetCone(dm, c, &cone)); 9318 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9319 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9320 for (cl = 0; cl < closureSize * 2; cl += 2) { 9321 const PetscInt p = closure[cl]; 9322 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9323 } 9324 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9325 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); 9326 for (f = 0; f < numFaces; ++f) { 9327 DMPolytopeType fct; 9328 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9329 9330 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9331 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9332 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9333 const PetscInt p = fclosure[cl]; 9334 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9335 } 9336 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]); 9337 for (v = 0; v < fnumCorners; ++v) { 9338 if (fclosure[v] != faces[fOff + v]) { 9339 PetscInt v1; 9340 9341 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9342 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9343 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9344 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9345 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9346 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]); 9347 } 9348 } 9349 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9350 fOff += faceSizes[f]; 9351 } 9352 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9353 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9354 } 9355 } 9356 PetscFunctionReturn(PETSC_SUCCESS); 9357 } 9358 9359 /*@ 9360 DMPlexCheckGeometry - Check the geometry of mesh cells 9361 9362 Input Parameter: 9363 . dm - The `DMPLEX` object 9364 9365 Level: developer 9366 9367 Notes: 9368 This is a useful diagnostic when creating meshes programmatically. 9369 9370 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9371 9372 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9373 @*/ 9374 PetscErrorCode DMPlexCheckGeometry(DM dm) 9375 { 9376 Vec coordinates; 9377 PetscReal detJ, J[9], refVol = 1.0; 9378 PetscReal vol; 9379 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9380 9381 PetscFunctionBegin; 9382 PetscCall(DMGetDimension(dm, &dim)); 9383 PetscCall(DMGetCoordinateDim(dm, &dE)); 9384 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9385 PetscCall(DMPlexGetDepth(dm, &depth)); 9386 for (d = 0; d < dim; ++d) refVol *= 2.0; 9387 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9388 /* Make sure local coordinates are created, because that step is collective */ 9389 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9390 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9391 for (c = cStart; c < cEnd; ++c) { 9392 DMPolytopeType ct; 9393 PetscInt unsplit; 9394 PetscBool ignoreZeroVol = PETSC_FALSE; 9395 9396 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9397 switch (ct) { 9398 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9399 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9400 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9401 ignoreZeroVol = PETSC_TRUE; 9402 break; 9403 default: 9404 break; 9405 } 9406 switch (ct) { 9407 case DM_POLYTOPE_TRI_PRISM: 9408 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9409 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9410 case DM_POLYTOPE_PYRAMID: 9411 continue; 9412 default: 9413 break; 9414 } 9415 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9416 if (unsplit) continue; 9417 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9418 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); 9419 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9420 /* This should work with periodicity since DG coordinates should be used */ 9421 if (depth > 1) { 9422 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9423 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); 9424 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9425 } 9426 } 9427 PetscFunctionReturn(PETSC_SUCCESS); 9428 } 9429 9430 /*@ 9431 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9432 9433 Collective 9434 9435 Input Parameters: 9436 + dm - The `DMPLEX` object 9437 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9438 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9439 9440 Level: developer 9441 9442 Notes: 9443 This is mainly intended for debugging/testing purposes. 9444 9445 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9446 9447 Extra roots can come from periodic cuts, where additional points appear on the boundary 9448 9449 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9450 @*/ 9451 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9452 { 9453 PetscInt l, nleaves, nroots, overlap; 9454 const PetscInt *locals; 9455 const PetscSFNode *remotes; 9456 PetscBool distributed; 9457 MPI_Comm comm; 9458 PetscMPIInt rank; 9459 9460 PetscFunctionBegin; 9461 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9462 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9463 else pointSF = dm->sf; 9464 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9465 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9466 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9467 { 9468 PetscMPIInt mpiFlag; 9469 9470 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9471 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9472 } 9473 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9474 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9475 if (!distributed) { 9476 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); 9477 PetscFunctionReturn(PETSC_SUCCESS); 9478 } 9479 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); 9480 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9481 9482 /* Check SF graph is compatible with DMPlex chart */ 9483 { 9484 PetscInt pStart, pEnd, maxLeaf; 9485 9486 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9487 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9488 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9489 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9490 } 9491 9492 /* Check Point SF has no local points referenced */ 9493 for (l = 0; l < nleaves; l++) { 9494 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); 9495 } 9496 9497 /* Check there are no cells in interface */ 9498 if (!overlap) { 9499 PetscInt cellHeight, cStart, cEnd; 9500 9501 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9502 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9503 for (l = 0; l < nleaves; ++l) { 9504 const PetscInt point = locals ? locals[l] : l; 9505 9506 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9507 } 9508 } 9509 9510 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9511 { 9512 const PetscInt *rootdegree; 9513 9514 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9515 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9516 for (l = 0; l < nleaves; ++l) { 9517 const PetscInt point = locals ? locals[l] : l; 9518 const PetscInt *cone; 9519 PetscInt coneSize, c, idx; 9520 9521 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9522 PetscCall(DMPlexGetCone(dm, point, &cone)); 9523 for (c = 0; c < coneSize; ++c) { 9524 if (!rootdegree[cone[c]]) { 9525 if (locals) { 9526 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9527 } else { 9528 idx = (cone[c] < nleaves) ? cone[c] : -1; 9529 } 9530 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9531 } 9532 } 9533 } 9534 } 9535 PetscFunctionReturn(PETSC_SUCCESS); 9536 } 9537 9538 /*@ 9539 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9540 9541 Collective 9542 9543 Input Parameter: 9544 . dm - The `DMPLEX` object 9545 9546 Level: developer 9547 9548 Notes: 9549 This is mainly intended for debugging/testing purposes. 9550 9551 Other cell types which are disconnected would be caught by the symmetry and face checks. 9552 9553 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9554 9555 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9556 @*/ 9557 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9558 { 9559 PetscInt pStart, pEnd, vStart, vEnd; 9560 9561 PetscFunctionBegin; 9562 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9563 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9564 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9565 for (PetscInt v = vStart; v < vEnd; ++v) { 9566 PetscInt suppSize; 9567 9568 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9569 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9570 } 9571 PetscFunctionReturn(PETSC_SUCCESS); 9572 } 9573 9574 /*@ 9575 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9576 9577 Input Parameter: 9578 . dm - The `DMPLEX` object 9579 9580 Level: developer 9581 9582 Notes: 9583 This is a useful diagnostic when creating meshes programmatically. 9584 9585 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9586 9587 Currently does not include `DMPlexCheckCellShape()`. 9588 9589 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9590 @*/ 9591 PetscErrorCode DMPlexCheck(DM dm) 9592 { 9593 PetscInt cellHeight; 9594 9595 PetscFunctionBegin; 9596 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9597 PetscCall(DMPlexCheckSymmetry(dm)); 9598 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9599 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9600 PetscCall(DMPlexCheckGeometry(dm)); 9601 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9602 PetscCall(DMPlexCheckInterfaceCones(dm)); 9603 PetscCall(DMPlexCheckOrphanVertices(dm)); 9604 PetscFunctionReturn(PETSC_SUCCESS); 9605 } 9606 9607 typedef struct cell_stats { 9608 PetscReal min, max, sum, squaresum; 9609 PetscInt count; 9610 } cell_stats_t; 9611 9612 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9613 { 9614 PetscInt i, N = *len; 9615 9616 for (i = 0; i < N; i++) { 9617 cell_stats_t *A = (cell_stats_t *)a; 9618 cell_stats_t *B = (cell_stats_t *)b; 9619 9620 B->min = PetscMin(A->min, B->min); 9621 B->max = PetscMax(A->max, B->max); 9622 B->sum += A->sum; 9623 B->squaresum += A->squaresum; 9624 B->count += A->count; 9625 } 9626 } 9627 9628 /*@ 9629 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9630 9631 Collective 9632 9633 Input Parameters: 9634 + dm - The `DMPLEX` object 9635 . output - If true, statistics will be displayed on `stdout` 9636 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9637 9638 Level: developer 9639 9640 Notes: 9641 This is mainly intended for debugging/testing purposes. 9642 9643 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9644 9645 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9646 @*/ 9647 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9648 { 9649 DM dmCoarse; 9650 cell_stats_t stats, globalStats; 9651 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9652 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9653 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9654 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9655 PetscMPIInt rank, size; 9656 9657 PetscFunctionBegin; 9658 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9659 stats.min = PETSC_MAX_REAL; 9660 stats.max = PETSC_MIN_REAL; 9661 stats.sum = stats.squaresum = 0.; 9662 stats.count = 0; 9663 9664 PetscCallMPI(MPI_Comm_size(comm, &size)); 9665 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9666 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9667 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9668 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9669 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9670 for (c = cStart; c < cEnd; c++) { 9671 PetscInt i; 9672 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9673 9674 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9675 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9676 for (i = 0; i < PetscSqr(cdim); ++i) { 9677 frobJ += J[i] * J[i]; 9678 frobInvJ += invJ[i] * invJ[i]; 9679 } 9680 cond2 = frobJ * frobInvJ; 9681 cond = PetscSqrtReal(cond2); 9682 9683 stats.min = PetscMin(stats.min, cond); 9684 stats.max = PetscMax(stats.max, cond); 9685 stats.sum += cond; 9686 stats.squaresum += cond2; 9687 stats.count++; 9688 if (output && cond > limit) { 9689 PetscSection coordSection; 9690 Vec coordsLocal; 9691 PetscScalar *coords = NULL; 9692 PetscInt Nv, d, clSize, cl, *closure = NULL; 9693 9694 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9695 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9696 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9697 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9698 for (i = 0; i < Nv / cdim; ++i) { 9699 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9700 for (d = 0; d < cdim; ++d) { 9701 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9702 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9703 } 9704 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9705 } 9706 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9707 for (cl = 0; cl < clSize * 2; cl += 2) { 9708 const PetscInt edge = closure[cl]; 9709 9710 if ((edge >= eStart) && (edge < eEnd)) { 9711 PetscReal len; 9712 9713 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9714 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9715 } 9716 } 9717 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9718 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9719 } 9720 } 9721 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9722 9723 if (size > 1) { 9724 PetscMPIInt blockLengths[2] = {4, 1}; 9725 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9726 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9727 MPI_Op statReduce; 9728 9729 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9730 PetscCallMPI(MPI_Type_commit(&statType)); 9731 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9732 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9733 PetscCallMPI(MPI_Op_free(&statReduce)); 9734 PetscCallMPI(MPI_Type_free(&statType)); 9735 } else { 9736 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9737 } 9738 if (rank == 0) { 9739 count = globalStats.count; 9740 min = globalStats.min; 9741 max = globalStats.max; 9742 mean = globalStats.sum / globalStats.count; 9743 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9744 } 9745 9746 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)); 9747 PetscCall(PetscFree2(J, invJ)); 9748 9749 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9750 if (dmCoarse) { 9751 PetscBool isplex; 9752 9753 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9754 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9755 } 9756 PetscFunctionReturn(PETSC_SUCCESS); 9757 } 9758 9759 /*@ 9760 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9761 orthogonal quality below given tolerance. 9762 9763 Collective 9764 9765 Input Parameters: 9766 + dm - The `DMPLEX` object 9767 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9768 - atol - [0, 1] Absolute tolerance for tagging cells. 9769 9770 Output Parameters: 9771 + OrthQual - `Vec` containing orthogonal quality per cell 9772 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9773 9774 Options Database Keys: 9775 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9776 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9777 9778 Level: intermediate 9779 9780 Notes: 9781 Orthogonal quality is given by the following formula\: 9782 9783 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9784 9785 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 9786 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9787 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9788 calculating the cosine of the angle between these vectors. 9789 9790 Orthogonal quality ranges from 1 (best) to 0 (worst). 9791 9792 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9793 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9794 9795 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9796 9797 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9798 @*/ 9799 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9800 { 9801 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9802 PetscInt *idx; 9803 PetscScalar *oqVals; 9804 const PetscScalar *cellGeomArr, *faceGeomArr; 9805 PetscReal *ci, *fi, *Ai; 9806 MPI_Comm comm; 9807 Vec cellgeom, facegeom; 9808 DM dmFace, dmCell; 9809 IS glob; 9810 ISLocalToGlobalMapping ltog; 9811 PetscViewer vwr; 9812 9813 PetscFunctionBegin; 9814 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9815 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9816 PetscAssertPointer(OrthQual, 4); 9817 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9818 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9819 PetscCall(DMGetDimension(dm, &nc)); 9820 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9821 { 9822 DMPlexInterpolatedFlag interpFlag; 9823 9824 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9825 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9826 PetscMPIInt rank; 9827 9828 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9829 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9830 } 9831 } 9832 if (OrthQualLabel) { 9833 PetscAssertPointer(OrthQualLabel, 5); 9834 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9835 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9836 } else { 9837 *OrthQualLabel = NULL; 9838 } 9839 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9840 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9841 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9842 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9843 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9844 PetscCall(VecCreate(comm, OrthQual)); 9845 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9846 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9847 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9848 PetscCall(VecSetUp(*OrthQual)); 9849 PetscCall(ISDestroy(&glob)); 9850 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9851 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9852 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9853 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9854 PetscCall(VecGetDM(cellgeom, &dmCell)); 9855 PetscCall(VecGetDM(facegeom, &dmFace)); 9856 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9857 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9858 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9859 PetscInt cellarr[2], *adj = NULL; 9860 PetscScalar *cArr, *fArr; 9861 PetscReal minvalc = 1.0, minvalf = 1.0; 9862 PetscFVCellGeom *cg; 9863 9864 idx[cellIter] = cell - cStart; 9865 cellarr[0] = cell; 9866 /* Make indexing into cellGeom easier */ 9867 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9868 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9869 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9870 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9871 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9872 PetscInt i; 9873 const PetscInt neigh = adj[cellneigh]; 9874 PetscReal normci = 0, normfi = 0, normai = 0; 9875 PetscFVCellGeom *cgneigh; 9876 PetscFVFaceGeom *fg; 9877 9878 /* Don't count ourselves in the neighbor list */ 9879 if (neigh == cell) continue; 9880 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9881 cellarr[1] = neigh; 9882 { 9883 PetscInt numcovpts; 9884 const PetscInt *covpts; 9885 9886 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9887 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9888 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9889 } 9890 9891 /* Compute c_i, f_i and their norms */ 9892 for (i = 0; i < nc; i++) { 9893 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9894 fi[i] = fg->centroid[i] - cg->centroid[i]; 9895 Ai[i] = fg->normal[i]; 9896 normci += PetscPowReal(ci[i], 2); 9897 normfi += PetscPowReal(fi[i], 2); 9898 normai += PetscPowReal(Ai[i], 2); 9899 } 9900 normci = PetscSqrtReal(normci); 9901 normfi = PetscSqrtReal(normfi); 9902 normai = PetscSqrtReal(normai); 9903 9904 /* Normalize and compute for each face-cell-normal pair */ 9905 for (i = 0; i < nc; i++) { 9906 ci[i] = ci[i] / normci; 9907 fi[i] = fi[i] / normfi; 9908 Ai[i] = Ai[i] / normai; 9909 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9910 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9911 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9912 } 9913 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9914 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9915 } 9916 PetscCall(PetscFree(adj)); 9917 PetscCall(PetscFree2(cArr, fArr)); 9918 /* Defer to cell if they're equal */ 9919 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9920 if (OrthQualLabel) { 9921 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9922 } 9923 } 9924 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9925 PetscCall(VecAssemblyBegin(*OrthQual)); 9926 PetscCall(VecAssemblyEnd(*OrthQual)); 9927 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9928 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9929 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9930 if (OrthQualLabel) { 9931 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9932 } 9933 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9934 PetscCall(PetscViewerDestroy(&vwr)); 9935 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9936 PetscFunctionReturn(PETSC_SUCCESS); 9937 } 9938 9939 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9940 * interpolator construction */ 9941 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9942 { 9943 PetscSection section, newSection, gsection; 9944 PetscSF sf; 9945 PetscBool hasConstraints, ghasConstraints; 9946 9947 PetscFunctionBegin; 9948 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9949 PetscAssertPointer(odm, 2); 9950 PetscCall(DMGetLocalSection(dm, §ion)); 9951 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9952 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9953 if (!ghasConstraints) { 9954 PetscCall(PetscObjectReference((PetscObject)dm)); 9955 *odm = dm; 9956 PetscFunctionReturn(PETSC_SUCCESS); 9957 } 9958 PetscCall(DMClone(dm, odm)); 9959 PetscCall(DMCopyFields(dm, *odm)); 9960 PetscCall(DMGetLocalSection(*odm, &newSection)); 9961 PetscCall(DMGetPointSF(*odm, &sf)); 9962 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9963 PetscCall(DMSetGlobalSection(*odm, gsection)); 9964 PetscCall(PetscSectionDestroy(&gsection)); 9965 PetscFunctionReturn(PETSC_SUCCESS); 9966 } 9967 9968 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9969 { 9970 DM dmco, dmfo; 9971 Mat interpo; 9972 Vec rscale; 9973 Vec cglobalo, clocal; 9974 Vec fglobal, fglobalo, flocal; 9975 PetscBool regular; 9976 9977 PetscFunctionBegin; 9978 PetscCall(DMGetFullDM(dmc, &dmco)); 9979 PetscCall(DMGetFullDM(dmf, &dmfo)); 9980 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9981 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9982 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9983 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9984 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9985 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9986 PetscCall(VecSet(cglobalo, 0.)); 9987 PetscCall(VecSet(clocal, 0.)); 9988 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9989 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9990 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9991 PetscCall(VecSet(fglobal, 0.)); 9992 PetscCall(VecSet(fglobalo, 0.)); 9993 PetscCall(VecSet(flocal, 0.)); 9994 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9995 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9996 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9997 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9998 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9999 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10000 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10001 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10002 *shift = fglobal; 10003 PetscCall(VecDestroy(&flocal)); 10004 PetscCall(VecDestroy(&fglobalo)); 10005 PetscCall(VecDestroy(&clocal)); 10006 PetscCall(VecDestroy(&cglobalo)); 10007 PetscCall(VecDestroy(&rscale)); 10008 PetscCall(MatDestroy(&interpo)); 10009 PetscCall(DMDestroy(&dmfo)); 10010 PetscCall(DMDestroy(&dmco)); 10011 PetscFunctionReturn(PETSC_SUCCESS); 10012 } 10013 10014 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10015 { 10016 PetscObject shifto; 10017 Vec shift; 10018 10019 PetscFunctionBegin; 10020 if (!interp) { 10021 Vec rscale; 10022 10023 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10024 PetscCall(VecDestroy(&rscale)); 10025 } else { 10026 PetscCall(PetscObjectReference((PetscObject)interp)); 10027 } 10028 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10029 if (!shifto) { 10030 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10031 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10032 shifto = (PetscObject)shift; 10033 PetscCall(VecDestroy(&shift)); 10034 } 10035 shift = (Vec)shifto; 10036 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10037 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10038 PetscCall(MatDestroy(&interp)); 10039 PetscFunctionReturn(PETSC_SUCCESS); 10040 } 10041 10042 /* Pointwise interpolation 10043 Just code FEM for now 10044 u^f = I u^c 10045 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10046 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10047 I_{ij} = psi^f_i phi^c_j 10048 */ 10049 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10050 { 10051 PetscSection gsc, gsf; 10052 PetscInt m, n; 10053 void *ctx; 10054 DM cdm; 10055 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10056 10057 PetscFunctionBegin; 10058 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10059 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10060 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10061 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10062 10063 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10064 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10065 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10066 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10067 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10068 10069 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10070 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10071 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10072 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10073 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10074 if (scaling) { 10075 /* Use naive scaling */ 10076 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10077 } 10078 PetscFunctionReturn(PETSC_SUCCESS); 10079 } 10080 10081 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10082 { 10083 VecScatter ctx; 10084 10085 PetscFunctionBegin; 10086 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10087 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10088 PetscCall(VecScatterDestroy(&ctx)); 10089 PetscFunctionReturn(PETSC_SUCCESS); 10090 } 10091 10092 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[]) 10093 { 10094 const PetscInt Nc = uOff[1] - uOff[0]; 10095 PetscInt c; 10096 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10097 } 10098 10099 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 10100 { 10101 DM dmc; 10102 PetscDS ds; 10103 Vec ones, locmass; 10104 IS cellIS; 10105 PetscFormKey key; 10106 PetscInt depth; 10107 10108 PetscFunctionBegin; 10109 PetscCall(DMClone(dm, &dmc)); 10110 PetscCall(DMCopyDisc(dm, dmc)); 10111 PetscCall(DMGetDS(dmc, &ds)); 10112 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10113 PetscCall(DMCreateGlobalVector(dmc, mass)); 10114 PetscCall(DMGetLocalVector(dmc, &ones)); 10115 PetscCall(DMGetLocalVector(dmc, &locmass)); 10116 PetscCall(DMPlexGetDepth(dmc, &depth)); 10117 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10118 PetscCall(VecSet(locmass, 0.0)); 10119 PetscCall(VecSet(ones, 1.0)); 10120 key.label = NULL; 10121 key.value = 0; 10122 key.field = 0; 10123 key.part = 0; 10124 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10125 PetscCall(ISDestroy(&cellIS)); 10126 PetscCall(VecSet(*mass, 0.0)); 10127 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 10128 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 10129 PetscCall(DMRestoreLocalVector(dmc, &ones)); 10130 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 10131 PetscCall(DMDestroy(&dmc)); 10132 PetscFunctionReturn(PETSC_SUCCESS); 10133 } 10134 10135 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10136 { 10137 PetscSection gsc, gsf; 10138 PetscInt m, n; 10139 void *ctx; 10140 DM cdm; 10141 PetscBool regular; 10142 10143 PetscFunctionBegin; 10144 if (dmFine == dmCoarse) { 10145 DM dmc; 10146 PetscDS ds; 10147 PetscWeakForm wf; 10148 Vec u; 10149 IS cellIS; 10150 PetscFormKey key; 10151 PetscInt depth; 10152 10153 PetscCall(DMClone(dmFine, &dmc)); 10154 PetscCall(DMCopyDisc(dmFine, dmc)); 10155 PetscCall(DMGetDS(dmc, &ds)); 10156 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10157 PetscCall(PetscWeakFormClear(wf)); 10158 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10159 PetscCall(DMCreateMatrix(dmc, mass)); 10160 PetscCall(DMGetLocalVector(dmc, &u)); 10161 PetscCall(DMPlexGetDepth(dmc, &depth)); 10162 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10163 PetscCall(MatZeroEntries(*mass)); 10164 key.label = NULL; 10165 key.value = 0; 10166 key.field = 0; 10167 key.part = 0; 10168 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10169 PetscCall(ISDestroy(&cellIS)); 10170 PetscCall(DMRestoreLocalVector(dmc, &u)); 10171 PetscCall(DMDestroy(&dmc)); 10172 } else { 10173 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10174 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10175 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10176 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10177 10178 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10179 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10180 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10181 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10182 10183 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10184 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10185 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10186 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10187 } 10188 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10189 PetscFunctionReturn(PETSC_SUCCESS); 10190 } 10191 10192 /*@ 10193 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10194 10195 Input Parameter: 10196 . dm - The `DMPLEX` object 10197 10198 Output Parameter: 10199 . regular - The flag 10200 10201 Level: intermediate 10202 10203 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10204 @*/ 10205 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10206 { 10207 PetscFunctionBegin; 10208 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10209 PetscAssertPointer(regular, 2); 10210 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10211 PetscFunctionReturn(PETSC_SUCCESS); 10212 } 10213 10214 /*@ 10215 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10216 10217 Input Parameters: 10218 + dm - The `DMPLEX` object 10219 - regular - The flag 10220 10221 Level: intermediate 10222 10223 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10224 @*/ 10225 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10226 { 10227 PetscFunctionBegin; 10228 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10229 ((DM_Plex *)dm->data)->regularRefinement = regular; 10230 PetscFunctionReturn(PETSC_SUCCESS); 10231 } 10232 10233 /*@ 10234 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10235 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10236 10237 Not Collective 10238 10239 Input Parameter: 10240 . dm - The `DMPLEX` object 10241 10242 Output Parameters: 10243 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10244 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10245 10246 Level: intermediate 10247 10248 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10249 @*/ 10250 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10251 { 10252 DM_Plex *plex = (DM_Plex *)dm->data; 10253 10254 PetscFunctionBegin; 10255 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10256 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10257 if (anchorSection) *anchorSection = plex->anchorSection; 10258 if (anchorIS) *anchorIS = plex->anchorIS; 10259 PetscFunctionReturn(PETSC_SUCCESS); 10260 } 10261 10262 /*@ 10263 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10264 10265 Collective 10266 10267 Input Parameters: 10268 + dm - The `DMPLEX` object 10269 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10270 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10271 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10272 10273 Level: intermediate 10274 10275 Notes: 10276 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10277 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10278 combination of other points' degrees of freedom. 10279 10280 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10281 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10282 10283 The reference counts of `anchorSection` and `anchorIS` are incremented. 10284 10285 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10286 @*/ 10287 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10288 { 10289 DM_Plex *plex = (DM_Plex *)dm->data; 10290 PetscMPIInt result; 10291 10292 PetscFunctionBegin; 10293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10294 if (anchorSection) { 10295 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10296 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10297 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10298 } 10299 if (anchorIS) { 10300 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10301 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10302 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10303 } 10304 10305 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10306 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10307 plex->anchorSection = anchorSection; 10308 10309 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10310 PetscCall(ISDestroy(&plex->anchorIS)); 10311 plex->anchorIS = anchorIS; 10312 10313 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10314 PetscInt size, a, pStart, pEnd; 10315 const PetscInt *anchors; 10316 10317 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10318 PetscCall(ISGetLocalSize(anchorIS, &size)); 10319 PetscCall(ISGetIndices(anchorIS, &anchors)); 10320 for (a = 0; a < size; a++) { 10321 PetscInt p; 10322 10323 p = anchors[a]; 10324 if (p >= pStart && p < pEnd) { 10325 PetscInt dof; 10326 10327 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10328 if (dof) { 10329 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10330 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10331 } 10332 } 10333 } 10334 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10335 } 10336 /* reset the generic constraints */ 10337 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10338 PetscFunctionReturn(PETSC_SUCCESS); 10339 } 10340 10341 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10342 { 10343 PetscSection anchorSection; 10344 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10345 10346 PetscFunctionBegin; 10347 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10348 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10349 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10350 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10351 if (numFields) { 10352 PetscInt f; 10353 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10354 10355 for (f = 0; f < numFields; f++) { 10356 PetscInt numComp; 10357 10358 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10359 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10360 } 10361 } 10362 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10363 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10364 pStart = PetscMax(pStart, sStart); 10365 pEnd = PetscMin(pEnd, sEnd); 10366 pEnd = PetscMax(pStart, pEnd); 10367 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10368 for (p = pStart; p < pEnd; p++) { 10369 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10370 if (dof) { 10371 PetscCall(PetscSectionGetDof(section, p, &dof)); 10372 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10373 for (f = 0; f < numFields; f++) { 10374 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10375 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10376 } 10377 } 10378 } 10379 PetscCall(PetscSectionSetUp(*cSec)); 10380 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10381 PetscFunctionReturn(PETSC_SUCCESS); 10382 } 10383 10384 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10385 { 10386 PetscSection aSec; 10387 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10388 const PetscInt *anchors; 10389 PetscInt numFields, f; 10390 IS aIS; 10391 MatType mtype; 10392 PetscBool iscuda, iskokkos; 10393 10394 PetscFunctionBegin; 10395 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10396 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10397 PetscCall(PetscSectionGetStorageSize(section, &n)); 10398 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10399 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10400 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10401 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10402 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10403 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10404 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10405 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10406 else mtype = MATSEQAIJ; 10407 PetscCall(MatSetType(*cMat, mtype)); 10408 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10409 PetscCall(ISGetIndices(aIS, &anchors)); 10410 /* cSec will be a subset of aSec and section */ 10411 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10412 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10413 PetscCall(PetscMalloc1(m + 1, &i)); 10414 i[0] = 0; 10415 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10416 for (p = pStart; p < pEnd; p++) { 10417 PetscInt rDof, rOff, r; 10418 10419 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10420 if (!rDof) continue; 10421 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10422 if (numFields) { 10423 for (f = 0; f < numFields; f++) { 10424 annz = 0; 10425 for (r = 0; r < rDof; r++) { 10426 a = anchors[rOff + r]; 10427 if (a < sStart || a >= sEnd) continue; 10428 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10429 annz += aDof; 10430 } 10431 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10432 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10433 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10434 } 10435 } else { 10436 annz = 0; 10437 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10438 for (q = 0; q < dof; q++) { 10439 a = anchors[rOff + q]; 10440 if (a < sStart || a >= sEnd) continue; 10441 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10442 annz += aDof; 10443 } 10444 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10445 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10446 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10447 } 10448 } 10449 nnz = i[m]; 10450 PetscCall(PetscMalloc1(nnz, &j)); 10451 offset = 0; 10452 for (p = pStart; p < pEnd; p++) { 10453 if (numFields) { 10454 for (f = 0; f < numFields; f++) { 10455 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10456 for (q = 0; q < dof; q++) { 10457 PetscInt rDof, rOff, r; 10458 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10459 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10460 for (r = 0; r < rDof; r++) { 10461 PetscInt s; 10462 10463 a = anchors[rOff + r]; 10464 if (a < sStart || a >= sEnd) continue; 10465 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10466 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10467 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10468 } 10469 } 10470 } 10471 } else { 10472 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10473 for (q = 0; q < dof; q++) { 10474 PetscInt rDof, rOff, r; 10475 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10476 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10477 for (r = 0; r < rDof; r++) { 10478 PetscInt s; 10479 10480 a = anchors[rOff + r]; 10481 if (a < sStart || a >= sEnd) continue; 10482 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10483 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10484 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10485 } 10486 } 10487 } 10488 } 10489 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10490 PetscCall(PetscFree(i)); 10491 PetscCall(PetscFree(j)); 10492 PetscCall(ISRestoreIndices(aIS, &anchors)); 10493 PetscFunctionReturn(PETSC_SUCCESS); 10494 } 10495 10496 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10497 { 10498 DM_Plex *plex = (DM_Plex *)dm->data; 10499 PetscSection anchorSection, section, cSec; 10500 Mat cMat; 10501 10502 PetscFunctionBegin; 10503 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10504 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10505 if (anchorSection) { 10506 PetscInt Nf; 10507 10508 PetscCall(DMGetLocalSection(dm, §ion)); 10509 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10510 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10511 PetscCall(DMGetNumFields(dm, &Nf)); 10512 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10513 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10514 PetscCall(PetscSectionDestroy(&cSec)); 10515 PetscCall(MatDestroy(&cMat)); 10516 } 10517 PetscFunctionReturn(PETSC_SUCCESS); 10518 } 10519 10520 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10521 { 10522 IS subis; 10523 PetscSection section, subsection; 10524 10525 PetscFunctionBegin; 10526 PetscCall(DMGetLocalSection(dm, §ion)); 10527 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10528 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10529 /* Create subdomain */ 10530 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10531 /* Create submodel */ 10532 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10533 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10534 PetscCall(DMSetLocalSection(*subdm, subsection)); 10535 PetscCall(PetscSectionDestroy(&subsection)); 10536 PetscCall(DMCopyDisc(dm, *subdm)); 10537 /* Create map from submodel to global model */ 10538 if (is) { 10539 PetscSection sectionGlobal, subsectionGlobal; 10540 IS spIS; 10541 const PetscInt *spmap; 10542 PetscInt *subIndices; 10543 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10544 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10545 10546 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10547 PetscCall(ISGetIndices(spIS, &spmap)); 10548 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10549 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10550 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10551 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10552 for (p = pStart; p < pEnd; ++p) { 10553 PetscInt gdof, pSubSize = 0; 10554 10555 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10556 if (gdof > 0) { 10557 for (f = 0; f < Nf; ++f) { 10558 PetscInt fdof, fcdof; 10559 10560 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10561 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10562 pSubSize += fdof - fcdof; 10563 } 10564 subSize += pSubSize; 10565 if (pSubSize) { 10566 if (bs < 0) { 10567 bs = pSubSize; 10568 } else if (bs != pSubSize) { 10569 /* Layout does not admit a pointwise block size */ 10570 bs = 1; 10571 } 10572 } 10573 } 10574 } 10575 /* Must have same blocksize on all procs (some might have no points) */ 10576 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10577 bsLocal[1] = bs; 10578 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10579 if (bsMinMax[0] != bsMinMax[1]) { 10580 bs = 1; 10581 } else { 10582 bs = bsMinMax[0]; 10583 } 10584 PetscCall(PetscMalloc1(subSize, &subIndices)); 10585 for (p = pStart; p < pEnd; ++p) { 10586 PetscInt gdof, goff; 10587 10588 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10589 if (gdof > 0) { 10590 const PetscInt point = spmap[p]; 10591 10592 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10593 for (f = 0; f < Nf; ++f) { 10594 PetscInt fdof, fcdof, fc, f2, poff = 0; 10595 10596 /* Can get rid of this loop by storing field information in the global section */ 10597 for (f2 = 0; f2 < f; ++f2) { 10598 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10599 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10600 poff += fdof - fcdof; 10601 } 10602 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10603 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10604 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10605 } 10606 } 10607 } 10608 PetscCall(ISRestoreIndices(spIS, &spmap)); 10609 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10610 if (bs > 1) { 10611 /* We need to check that the block size does not come from non-contiguous fields */ 10612 PetscInt i, j, set = 1; 10613 for (i = 0; i < subSize; i += bs) { 10614 for (j = 0; j < bs; ++j) { 10615 if (subIndices[i + j] != subIndices[i] + j) { 10616 set = 0; 10617 break; 10618 } 10619 } 10620 } 10621 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10622 } 10623 /* Attach nullspace */ 10624 for (f = 0; f < Nf; ++f) { 10625 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10626 if ((*subdm)->nullspaceConstructors[f]) break; 10627 } 10628 if (f < Nf) { 10629 MatNullSpace nullSpace; 10630 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10631 10632 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10633 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10634 } 10635 } 10636 PetscFunctionReturn(PETSC_SUCCESS); 10637 } 10638 10639 /*@ 10640 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10641 10642 Input Parameters: 10643 + dm - The `DM` 10644 - dummy - unused argument 10645 10646 Options Database Key: 10647 . -dm_plex_monitor_throughput - Activate the monitor 10648 10649 Level: developer 10650 10651 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10652 @*/ 10653 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10654 { 10655 PetscLogHandler default_handler; 10656 10657 PetscFunctionBegin; 10658 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10659 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10660 if (default_handler) { 10661 PetscLogEvent event; 10662 PetscEventPerfInfo eventInfo; 10663 PetscReal cellRate, flopRate; 10664 PetscInt cStart, cEnd, Nf, N; 10665 const char *name; 10666 10667 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10668 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10669 PetscCall(DMGetNumFields(dm, &Nf)); 10670 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10671 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10672 N = (cEnd - cStart) * Nf * eventInfo.count; 10673 flopRate = eventInfo.flops / eventInfo.time; 10674 cellRate = N / eventInfo.time; 10675 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))); 10676 } else { 10677 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."); 10678 } 10679 PetscFunctionReturn(PETSC_SUCCESS); 10680 } 10681