1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 15 16 PetscBool Plexcite = PETSC_FALSE; 17 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 18 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 19 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 20 "journal = {SIAM Journal on Scientific Computing},\n" 21 "volume = {38},\n" 22 "number = {5},\n" 23 "pages = {S143--S155},\n" 24 "eprint = {http://arxiv.org/abs/1506.07749},\n" 25 "doi = {10.1137/15M1026092},\n" 26 "year = {2016},\n" 27 "petsc_uses={DMPlex},\n}\n"; 28 29 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 30 31 /*@ 32 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 33 34 Input Parameter: 35 . dm - The `DMPLEX` object 36 37 Output Parameter: 38 . simplex - Flag checking for a simplex 39 40 Level: intermediate 41 42 Note: 43 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 44 If the mesh has no cells, this returns `PETSC_FALSE`. 45 46 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 47 @*/ 48 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 49 { 50 DMPolytopeType ct; 51 PetscInt cStart, cEnd; 52 53 PetscFunctionBegin; 54 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 55 if (cEnd <= cStart) { 56 *simplex = PETSC_FALSE; 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 60 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 64 /*@ 65 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 66 67 Input Parameters: 68 + dm - The `DMPLEX` object 69 - height - The cell height in the Plex, 0 is the default 70 71 Output Parameters: 72 + cStart - The first "normal" cell 73 - cEnd - The upper bound on "normal" cells 74 75 Level: developer 76 77 Note: 78 This function requires that tensor cells are ordered last. 79 80 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 81 @*/ 82 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 83 { 84 DMLabel ctLabel; 85 IS valueIS; 86 const PetscInt *ctypes; 87 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 88 89 PetscFunctionBegin; 90 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 91 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 92 PetscCall(ISGetLocalSize(valueIS, &Nct)); 93 PetscCall(ISGetIndices(valueIS, &ctypes)); 94 if (!Nct) cS = cE = 0; 95 for (PetscInt t = 0; t < Nct; ++t) { 96 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 97 PetscInt ctS, ctE, ht; 98 99 if (ct == DM_POLYTOPE_UNKNOWN) { 100 // If any cells are not typed, just use all cells 101 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 102 break; 103 } 104 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 105 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 106 if (ctS >= ctE) continue; 107 // Check that a point has the right height 108 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 109 if (ht != height) continue; 110 cS = PetscMin(cS, ctS); 111 cE = PetscMax(cE, ctE); 112 } 113 PetscCall(ISDestroy(&valueIS)); 114 // Reset label for fast lookup 115 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 116 if (cStart) *cStart = cS; 117 if (cEnd) *cEnd = cE; 118 PetscFunctionReturn(PETSC_SUCCESS); 119 } 120 121 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 122 { 123 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 124 PetscInt *sStart, *sEnd; 125 PetscViewerVTKFieldType *ft; 126 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 127 DMLabel depthLabel, ctLabel; 128 129 PetscFunctionBegin; 130 131 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 132 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 133 PetscCall(DMGetCoordinateDim(dm, &cdim)); 134 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 135 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 136 if (field >= 0) { 137 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 138 } else { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 140 } 141 142 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 143 PetscCall(DMPlexGetDepth(dm, &depth)); 144 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 145 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 146 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 147 const DMPolytopeType ict = (DMPolytopeType)c; 148 PetscInt dep; 149 150 if (ict == DM_POLYTOPE_FV_GHOST) continue; 151 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 152 if (pStart >= 0) { 153 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 154 if (dep != depth - cellHeight) continue; 155 } 156 if (field >= 0) { 157 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 158 } else { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 160 } 161 } 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_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer)); 1047 PetscCall(PetscViewerFlush(viewer)); 1048 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1049 const char *name, *color; 1050 const char *defcolors[3] = {"gray", "orange", "green"}; 1051 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1052 char lname[PETSC_MAX_PATH_LEN]; 1053 PetscReal scale = 2.0; 1054 PetscReal tikzscale = 1.0; 1055 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1056 double tcoords[3]; 1057 PetscScalar *coords; 1058 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 1059 PetscMPIInt rank, size; 1060 char **names, **colors, **lcolors; 1061 PetscBool flg, lflg; 1062 PetscBT wp = NULL; 1063 PetscInt pEnd, pStart; 1064 1065 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1066 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1067 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1068 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1069 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1070 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1071 PetscCall(DMGetDimension(dm, &dim)); 1072 PetscCall(DMPlexGetDepth(dm, &depth)); 1073 PetscCall(DMGetNumLabels(dm, &numLabels)); 1074 numLabels = PetscMax(numLabels, 10); 1075 numColors = 10; 1076 numLColors = 10; 1077 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1078 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1079 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1080 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1081 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1082 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1083 n = 4; 1084 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1085 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1086 n = 4; 1087 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1088 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1089 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1090 if (!useLabels) numLabels = 0; 1091 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1092 if (!useColors) { 1093 numColors = 3; 1094 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1095 } 1096 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1097 if (!useColors) { 1098 numLColors = 4; 1099 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1100 } 1101 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1102 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1103 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1104 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1105 if (depth < dim) plotEdges = PETSC_FALSE; 1106 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1107 1108 /* filter points with labelvalue != labeldefaultvalue */ 1109 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1110 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1111 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1112 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1113 if (lflg) { 1114 DMLabel lbl; 1115 1116 PetscCall(DMGetLabel(dm, lname, &lbl)); 1117 if (lbl) { 1118 PetscInt val, defval; 1119 1120 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1121 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1122 for (c = pStart; c < pEnd; c++) { 1123 PetscInt *closure = NULL; 1124 PetscInt closureSize; 1125 1126 PetscCall(DMLabelGetValue(lbl, c, &val)); 1127 if (val == defval) continue; 1128 1129 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1130 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1131 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1132 } 1133 } 1134 } 1135 1136 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1137 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1138 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1139 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1140 \\documentclass[tikz]{standalone}\n\n\ 1141 \\usepackage{pgflibraryshapes}\n\ 1142 \\usetikzlibrary{backgrounds}\n\ 1143 \\usetikzlibrary{arrows}\n\ 1144 \\begin{document}\n")); 1145 if (size > 1) { 1146 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1147 for (p = 0; p < size; ++p) { 1148 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1149 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1150 } 1151 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1152 } 1153 if (drawHasse) { 1154 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1155 1156 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1157 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1158 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1168 } 1169 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1170 1171 /* Plot vertices */ 1172 PetscCall(VecGetArray(coordinates, &coords)); 1173 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1174 for (v = vStart; v < vEnd; ++v) { 1175 PetscInt off, dof, d; 1176 PetscBool isLabeled = PETSC_FALSE; 1177 1178 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1179 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1180 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1181 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1182 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1183 for (d = 0; d < dof; ++d) { 1184 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1185 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1186 } 1187 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1188 if (dim == 3) { 1189 PetscReal tmp = tcoords[1]; 1190 tcoords[1] = tcoords[2]; 1191 tcoords[2] = -tmp; 1192 } 1193 for (d = 0; d < dof; ++d) { 1194 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1195 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1196 } 1197 if (drawHasse) color = colors[0 % numColors]; 1198 else color = colors[rank % numColors]; 1199 for (l = 0; l < numLabels; ++l) { 1200 PetscInt val; 1201 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1202 if (val >= 0) { 1203 color = lcolors[l % numLColors]; 1204 isLabeled = PETSC_TRUE; 1205 break; 1206 } 1207 } 1208 if (drawNumbers[0]) { 1209 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1210 } else if (drawColors[0]) { 1211 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1212 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1213 } 1214 PetscCall(VecRestoreArray(coordinates, &coords)); 1215 PetscCall(PetscViewerFlush(viewer)); 1216 /* Plot edges */ 1217 if (plotEdges) { 1218 PetscCall(VecGetArray(coordinates, &coords)); 1219 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1220 for (e = eStart; e < eEnd; ++e) { 1221 const PetscInt *cone; 1222 PetscInt coneSize, offA, offB, dof, d; 1223 1224 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1225 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1226 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1227 PetscCall(DMPlexGetCone(dm, e, &cone)); 1228 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1229 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1230 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1231 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1232 for (d = 0; d < dof; ++d) { 1233 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1234 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1235 } 1236 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1237 if (dim == 3) { 1238 PetscReal tmp = tcoords[1]; 1239 tcoords[1] = tcoords[2]; 1240 tcoords[2] = -tmp; 1241 } 1242 for (d = 0; d < dof; ++d) { 1243 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1244 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1245 } 1246 if (drawHasse) color = colors[1 % numColors]; 1247 else color = colors[rank % numColors]; 1248 for (l = 0; l < numLabels; ++l) { 1249 PetscInt val; 1250 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1251 if (val >= 0) { 1252 color = lcolors[l % numLColors]; 1253 break; 1254 } 1255 } 1256 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1257 } 1258 PetscCall(VecRestoreArray(coordinates, &coords)); 1259 PetscCall(PetscViewerFlush(viewer)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1261 } 1262 /* Plot cells */ 1263 if (dim == 3 || !drawNumbers[1]) { 1264 for (e = eStart; e < eEnd; ++e) { 1265 const PetscInt *cone; 1266 1267 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1268 color = colors[rank % numColors]; 1269 for (l = 0; l < numLabels; ++l) { 1270 PetscInt val; 1271 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1272 if (val >= 0) { 1273 color = lcolors[l % numLColors]; 1274 break; 1275 } 1276 } 1277 PetscCall(DMPlexGetCone(dm, e, &cone)); 1278 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1279 } 1280 } else { 1281 DMPolytopeType ct; 1282 1283 /* Drawing a 2D polygon */ 1284 for (c = cStart; c < cEnd; ++c) { 1285 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1286 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1287 if (DMPolytopeTypeIsHybrid(ct)) { 1288 const PetscInt *cone; 1289 PetscInt coneSize, e; 1290 1291 PetscCall(DMPlexGetCone(dm, c, &cone)); 1292 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1293 for (e = 0; e < coneSize; ++e) { 1294 const PetscInt *econe; 1295 1296 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1297 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1298 } 1299 } else { 1300 PetscInt *closure = NULL; 1301 PetscInt closureSize, Nv = 0, v; 1302 1303 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1304 for (p = 0; p < closureSize * 2; p += 2) { 1305 const PetscInt point = closure[p]; 1306 1307 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1308 } 1309 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1310 for (v = 0; v <= Nv; ++v) { 1311 const PetscInt vertex = closure[v % Nv]; 1312 1313 if (v > 0) { 1314 if (plotEdges) { 1315 const PetscInt *edge; 1316 PetscInt endpoints[2], ne; 1317 1318 endpoints[0] = closure[v - 1]; 1319 endpoints[1] = vertex; 1320 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1321 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1322 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1323 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1324 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1325 } 1326 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1327 } 1328 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1329 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1330 } 1331 } 1332 } 1333 for (c = cStart; c < cEnd; ++c) { 1334 double ccoords[3] = {0.0, 0.0, 0.0}; 1335 PetscBool isLabeled = PETSC_FALSE; 1336 PetscScalar *cellCoords = NULL; 1337 const PetscScalar *array; 1338 PetscInt numCoords, cdim, d; 1339 PetscBool isDG; 1340 1341 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1342 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1343 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1344 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1345 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1346 for (p = 0; p < numCoords / cdim; ++p) { 1347 for (d = 0; d < cdim; ++d) { 1348 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1349 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1350 } 1351 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1352 if (cdim == 3) { 1353 PetscReal tmp = tcoords[1]; 1354 tcoords[1] = tcoords[2]; 1355 tcoords[2] = -tmp; 1356 } 1357 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1358 } 1359 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1360 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1361 for (d = 0; d < cdim; ++d) { 1362 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1363 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1364 } 1365 if (drawHasse) color = colors[depth % numColors]; 1366 else color = colors[rank % numColors]; 1367 for (l = 0; l < numLabels; ++l) { 1368 PetscInt val; 1369 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1370 if (val >= 0) { 1371 color = lcolors[l % numLColors]; 1372 isLabeled = PETSC_TRUE; 1373 break; 1374 } 1375 } 1376 if (drawNumbers[dim]) { 1377 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1378 } else if (drawColors[dim]) { 1379 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1380 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1381 } 1382 if (drawHasse) { 1383 color = colors[depth % numColors]; 1384 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1385 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1386 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1387 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1388 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1389 1390 color = colors[1 % numColors]; 1391 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1392 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1393 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1394 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1396 1397 color = colors[0 % numColors]; 1398 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1399 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1403 1404 for (p = pStart; p < pEnd; ++p) { 1405 const PetscInt *cone; 1406 PetscInt coneSize, cp; 1407 1408 PetscCall(DMPlexGetCone(dm, p, &cone)); 1409 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1410 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1411 } 1412 } 1413 PetscCall(PetscViewerFlush(viewer)); 1414 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1415 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1417 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1418 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1419 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1420 PetscCall(PetscFree3(names, colors, lcolors)); 1421 PetscCall(PetscBTDestroy(&wp)); 1422 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1423 Vec cown, acown; 1424 VecScatter sct; 1425 ISLocalToGlobalMapping g2l; 1426 IS gid, acis; 1427 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1428 MPI_Group ggroup, ngroup; 1429 PetscScalar *array, nid; 1430 const PetscInt *idxs; 1431 PetscInt *idxs2, *start, *adjacency, *work; 1432 PetscInt64 lm[3], gm[3]; 1433 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1434 PetscMPIInt d1, d2, rank; 1435 1436 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1437 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1438 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1439 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1440 #endif 1441 if (ncomm != MPI_COMM_NULL) { 1442 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1443 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1444 d1 = 0; 1445 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1446 nid = d2; 1447 PetscCallMPI(MPI_Group_free(&ggroup)); 1448 PetscCallMPI(MPI_Group_free(&ngroup)); 1449 PetscCallMPI(MPI_Comm_free(&ncomm)); 1450 } else nid = 0.0; 1451 1452 /* Get connectivity */ 1453 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1454 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1455 1456 /* filter overlapped local cells */ 1457 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1458 PetscCall(ISGetIndices(gid, &idxs)); 1459 PetscCall(ISGetLocalSize(gid, &cum)); 1460 PetscCall(PetscMalloc1(cum, &idxs2)); 1461 for (c = cStart, cum = 0; c < cEnd; c++) { 1462 if (idxs[c - cStart] < 0) continue; 1463 idxs2[cum++] = idxs[c - cStart]; 1464 } 1465 PetscCall(ISRestoreIndices(gid, &idxs)); 1466 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1467 PetscCall(ISDestroy(&gid)); 1468 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1469 1470 /* support for node-aware cell locality */ 1471 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1472 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1473 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1474 PetscCall(VecGetArray(cown, &array)); 1475 for (c = 0; c < numVertices; c++) array[c] = nid; 1476 PetscCall(VecRestoreArray(cown, &array)); 1477 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1478 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1479 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1480 PetscCall(ISDestroy(&acis)); 1481 PetscCall(VecScatterDestroy(&sct)); 1482 PetscCall(VecDestroy(&cown)); 1483 1484 /* compute edgeCut */ 1485 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1486 PetscCall(PetscMalloc1(cum, &work)); 1487 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1488 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1489 PetscCall(ISDestroy(&gid)); 1490 PetscCall(VecGetArray(acown, &array)); 1491 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1492 PetscInt totl; 1493 1494 totl = start[c + 1] - start[c]; 1495 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1496 for (i = 0; i < totl; i++) { 1497 if (work[i] < 0) { 1498 ect += 1; 1499 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1500 } 1501 } 1502 } 1503 PetscCall(PetscFree(work)); 1504 PetscCall(VecRestoreArray(acown, &array)); 1505 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1506 lm[1] = -numVertices; 1507 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1509 lm[0] = ect; /* edgeCut */ 1510 lm[1] = ectn; /* node-aware edgeCut */ 1511 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1512 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1513 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1514 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1515 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1516 #else 1517 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1518 #endif 1519 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1520 PetscCall(PetscFree(start)); 1521 PetscCall(PetscFree(adjacency)); 1522 PetscCall(VecDestroy(&acown)); 1523 } else { 1524 const char *name; 1525 PetscInt *sizes, *hybsizes, *ghostsizes; 1526 PetscInt locDepth, depth, cellHeight, dim, d; 1527 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1528 PetscInt numLabels, l, maxSize = 17; 1529 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1530 MPI_Comm comm; 1531 PetscMPIInt size, rank; 1532 1533 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1534 PetscCallMPI(MPI_Comm_size(comm, &size)); 1535 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1536 PetscCall(DMGetDimension(dm, &dim)); 1537 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1538 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1539 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1540 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1541 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1542 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1543 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1544 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1545 gcNum = gcEnd - gcStart; 1546 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1547 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1548 for (d = 0; d <= depth; d++) { 1549 PetscInt Nc[2] = {0, 0}, ict; 1550 1551 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1552 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1553 ict = ct0; 1554 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1555 ct0 = (DMPolytopeType)ict; 1556 for (p = pStart; p < pEnd; ++p) { 1557 DMPolytopeType ct; 1558 1559 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1560 if (ct == ct0) ++Nc[0]; 1561 else ++Nc[1]; 1562 } 1563 if (size < maxSize) { 1564 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1565 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1566 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1567 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1568 for (p = 0; p < size; ++p) { 1569 if (rank == 0) { 1570 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1571 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1572 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1573 } 1574 } 1575 } else { 1576 PetscInt locMinMax[2]; 1577 1578 locMinMax[0] = Nc[0] + Nc[1]; 1579 locMinMax[1] = Nc[0] + Nc[1]; 1580 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1581 locMinMax[0] = Nc[1]; 1582 locMinMax[1] = Nc[1]; 1583 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1584 if (d == depth) { 1585 locMinMax[0] = gcNum; 1586 locMinMax[1] = gcNum; 1587 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1588 } 1589 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1590 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1591 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1592 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1593 } 1594 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1595 } 1596 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1597 { 1598 const PetscReal *maxCell; 1599 const PetscReal *L; 1600 PetscBool localized; 1601 1602 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1603 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1604 if (L || localized) { 1605 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1606 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1607 if (L) { 1608 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1609 for (d = 0; d < dim; ++d) { 1610 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1611 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1612 } 1613 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1614 } 1615 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1616 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1617 } 1618 } 1619 PetscCall(DMGetNumLabels(dm, &numLabels)); 1620 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1621 for (l = 0; l < numLabels; ++l) { 1622 DMLabel label; 1623 const char *name; 1624 IS valueIS; 1625 const PetscInt *values; 1626 PetscInt numValues, v; 1627 1628 PetscCall(DMGetLabelName(dm, l, &name)); 1629 PetscCall(DMGetLabel(dm, name, &label)); 1630 PetscCall(DMLabelGetNumValues(label, &numValues)); 1631 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1632 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1633 PetscCall(ISGetIndices(valueIS, &values)); 1634 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1635 for (v = 0; v < numValues; ++v) { 1636 PetscInt size; 1637 1638 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1639 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1640 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1641 } 1642 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1643 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1644 PetscCall(ISRestoreIndices(valueIS, &values)); 1645 PetscCall(ISDestroy(&valueIS)); 1646 } 1647 { 1648 char **labelNames; 1649 PetscInt Nl = numLabels; 1650 PetscBool flg; 1651 1652 PetscCall(PetscMalloc1(Nl, &labelNames)); 1653 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1654 for (l = 0; l < Nl; ++l) { 1655 DMLabel label; 1656 1657 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1658 if (flg) { 1659 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1660 PetscCall(DMLabelView(label, viewer)); 1661 } 1662 PetscCall(PetscFree(labelNames[l])); 1663 } 1664 PetscCall(PetscFree(labelNames)); 1665 } 1666 /* If no fields are specified, people do not want to see adjacency */ 1667 if (dm->Nf) { 1668 PetscInt f; 1669 1670 for (f = 0; f < dm->Nf; ++f) { 1671 const char *name; 1672 1673 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1674 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1675 PetscCall(PetscViewerASCIIPushTab(viewer)); 1676 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1677 if (dm->fields[f].adjacency[0]) { 1678 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1679 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1680 } else { 1681 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1682 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1683 } 1684 PetscCall(PetscViewerASCIIPopTab(viewer)); 1685 } 1686 } 1687 PetscCall(DMGetCoarseDM(dm, &cdm)); 1688 if (cdm) { 1689 PetscCall(PetscViewerASCIIPushTab(viewer)); 1690 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1691 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1692 PetscCall(PetscViewerASCIIPopTab(viewer)); 1693 } 1694 } 1695 PetscFunctionReturn(PETSC_SUCCESS); 1696 } 1697 1698 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1699 { 1700 DMPolytopeType ct; 1701 PetscMPIInt rank; 1702 PetscInt cdim; 1703 1704 PetscFunctionBegin; 1705 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1706 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1707 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1708 switch (ct) { 1709 case DM_POLYTOPE_SEGMENT: 1710 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1711 switch (cdim) { 1712 case 1: { 1713 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1714 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1715 1716 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1717 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1718 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1719 } break; 1720 case 2: { 1721 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1722 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1723 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1724 1725 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1726 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1727 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1728 } break; 1729 default: 1730 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1731 } 1732 break; 1733 case DM_POLYTOPE_TRIANGLE: 1734 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1735 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1736 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1737 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1738 break; 1739 case DM_POLYTOPE_QUADRILATERAL: 1740 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1741 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1742 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1743 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1744 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1745 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1746 break; 1747 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1748 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1749 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1750 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1751 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1752 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1753 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1754 break; 1755 case DM_POLYTOPE_FV_GHOST: 1756 break; 1757 default: 1758 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1759 } 1760 PetscFunctionReturn(PETSC_SUCCESS); 1761 } 1762 1763 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1764 { 1765 PetscReal centroid[2] = {0., 0.}; 1766 PetscMPIInt rank; 1767 PetscInt fillColor; 1768 1769 PetscFunctionBegin; 1770 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1771 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1772 for (PetscInt v = 0; v < Nv; ++v) { 1773 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1774 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1775 } 1776 for (PetscInt e = 0; e < Nv; ++e) { 1777 refCoords[0] = refVertices[e * 2 + 0]; 1778 refCoords[1] = refVertices[e * 2 + 1]; 1779 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1780 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1781 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1782 } 1783 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1784 for (PetscInt d = 0; d < edgeDiv; ++d) { 1785 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)); 1786 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1787 } 1788 } 1789 PetscFunctionReturn(PETSC_SUCCESS); 1790 } 1791 1792 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1793 { 1794 DMPolytopeType ct; 1795 1796 PetscFunctionBegin; 1797 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1798 switch (ct) { 1799 case DM_POLYTOPE_TRIANGLE: { 1800 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1801 1802 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1803 } break; 1804 case DM_POLYTOPE_QUADRILATERAL: { 1805 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1806 1807 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1808 } break; 1809 default: 1810 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1811 } 1812 PetscFunctionReturn(PETSC_SUCCESS); 1813 } 1814 1815 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1816 { 1817 PetscDraw draw; 1818 DM cdm; 1819 PetscSection coordSection; 1820 Vec coordinates; 1821 PetscReal xyl[3], xyr[3]; 1822 PetscReal *refCoords, *edgeCoords; 1823 PetscBool isnull, drawAffine; 1824 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1825 1826 PetscFunctionBegin; 1827 PetscCall(DMGetCoordinateDim(dm, &dim)); 1828 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1829 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1830 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1831 edgeDiv = cDegree + 1; 1832 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1833 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1834 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1835 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1836 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1837 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1838 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1839 1840 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1841 PetscCall(PetscDrawIsNull(draw, &isnull)); 1842 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1843 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1844 1845 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1846 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1847 PetscCall(PetscDrawClear(draw)); 1848 1849 for (c = cStart; c < cEnd; ++c) { 1850 PetscScalar *coords = NULL; 1851 const PetscScalar *coords_arr; 1852 PetscInt numCoords; 1853 PetscBool isDG; 1854 1855 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1856 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1857 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1858 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1859 } 1860 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1861 PetscCall(PetscDrawFlush(draw)); 1862 PetscCall(PetscDrawPause(draw)); 1863 PetscCall(PetscDrawSave(draw)); 1864 PetscFunctionReturn(PETSC_SUCCESS); 1865 } 1866 1867 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1868 { 1869 DM odm = dm, rdm = dm, cdm; 1870 PetscFE fe; 1871 PetscSpace sp; 1872 PetscClassId id; 1873 PetscInt degree; 1874 PetscBool hoView = PETSC_TRUE; 1875 1876 PetscFunctionBegin; 1877 PetscObjectOptionsBegin((PetscObject)dm); 1878 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1879 PetscOptionsEnd(); 1880 PetscCall(PetscObjectReference((PetscObject)dm)); 1881 *hdm = dm; 1882 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1883 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1884 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1885 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1886 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1887 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1888 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1889 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1890 DM cdm, rcdm; 1891 Mat In; 1892 Vec cl, rcl; 1893 1894 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1895 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1896 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1897 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1898 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1899 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1900 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1901 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1902 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1903 PetscCall(MatMult(In, cl, rcl)); 1904 PetscCall(MatDestroy(&In)); 1905 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1906 PetscCall(DMDestroy(&odm)); 1907 odm = rdm; 1908 } 1909 *hdm = rdm; 1910 PetscFunctionReturn(PETSC_SUCCESS); 1911 } 1912 1913 #if defined(PETSC_HAVE_EXODUSII) 1914 #include <exodusII.h> 1915 #include <petscviewerexodusii.h> 1916 #endif 1917 1918 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1919 { 1920 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1921 char name[PETSC_MAX_PATH_LEN]; 1922 1923 PetscFunctionBegin; 1924 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1925 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1926 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1927 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1928 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1929 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1930 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1931 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1932 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1933 if (iascii) { 1934 PetscViewerFormat format; 1935 PetscCall(PetscViewerGetFormat(viewer, &format)); 1936 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1937 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1938 } else if (ishdf5) { 1939 #if defined(PETSC_HAVE_HDF5) 1940 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1941 #else 1942 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1943 #endif 1944 } else if (isvtk) { 1945 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1946 } else if (isdraw) { 1947 DM hdm; 1948 1949 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1950 PetscCall(DMPlexView_Draw(hdm, viewer)); 1951 PetscCall(DMDestroy(&hdm)); 1952 } else if (isglvis) { 1953 PetscCall(DMPlexView_GLVis(dm, viewer)); 1954 #if defined(PETSC_HAVE_EXODUSII) 1955 } else if (isexodus) { 1956 /* 1957 exodusII requires that all sets be part of exactly one cell set. 1958 If the dm does not have a "Cell Sets" label defined, we create one 1959 with ID 1, containing all cells. 1960 Note that if the Cell Sets label is defined but does not cover all cells, 1961 we may still have a problem. This should probably be checked here or in the viewer; 1962 */ 1963 PetscInt numCS; 1964 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1965 if (!numCS) { 1966 PetscInt cStart, cEnd, c; 1967 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1968 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1969 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1970 } 1971 PetscCall(DMView_PlexExodusII(dm, viewer)); 1972 #endif 1973 #if defined(PETSC_HAVE_CGNS) 1974 } else if (iscgns) { 1975 PetscCall(DMView_PlexCGNS(dm, viewer)); 1976 #endif 1977 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1978 /* Optionally view the partition */ 1979 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1980 if (flg) { 1981 Vec ranks; 1982 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1983 PetscCall(VecView(ranks, viewer)); 1984 PetscCall(VecDestroy(&ranks)); 1985 } 1986 /* Optionally view a label */ 1987 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1988 if (flg) { 1989 DMLabel label; 1990 Vec val; 1991 1992 PetscCall(DMGetLabel(dm, name, &label)); 1993 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1994 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1995 PetscCall(VecView(val, viewer)); 1996 PetscCall(VecDestroy(&val)); 1997 } 1998 PetscFunctionReturn(PETSC_SUCCESS); 1999 } 2000 2001 /*@ 2002 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2003 2004 Collective 2005 2006 Input Parameters: 2007 + dm - The `DM` whose topology is to be saved 2008 - viewer - The `PetscViewer` to save it in 2009 2010 Level: advanced 2011 2012 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2013 @*/ 2014 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2015 { 2016 PetscBool ishdf5; 2017 2018 PetscFunctionBegin; 2019 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2020 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2021 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2022 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2023 if (ishdf5) { 2024 #if defined(PETSC_HAVE_HDF5) 2025 PetscViewerFormat format; 2026 PetscCall(PetscViewerGetFormat(viewer, &format)); 2027 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2028 IS globalPointNumbering; 2029 2030 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2031 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2032 PetscCall(ISDestroy(&globalPointNumbering)); 2033 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2034 #else 2035 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2036 #endif 2037 } 2038 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2039 PetscFunctionReturn(PETSC_SUCCESS); 2040 } 2041 2042 /*@ 2043 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2044 2045 Collective 2046 2047 Input Parameters: 2048 + dm - The `DM` whose coordinates are to be saved 2049 - viewer - The `PetscViewer` for saving 2050 2051 Level: advanced 2052 2053 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2054 @*/ 2055 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2056 { 2057 PetscBool ishdf5; 2058 2059 PetscFunctionBegin; 2060 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2061 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2062 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2063 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2064 if (ishdf5) { 2065 #if defined(PETSC_HAVE_HDF5) 2066 PetscViewerFormat format; 2067 PetscCall(PetscViewerGetFormat(viewer, &format)); 2068 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2069 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2070 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2071 #else 2072 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2073 #endif 2074 } 2075 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2076 PetscFunctionReturn(PETSC_SUCCESS); 2077 } 2078 2079 /*@ 2080 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2081 2082 Collective 2083 2084 Input Parameters: 2085 + dm - The `DM` whose labels are to be saved 2086 - viewer - The `PetscViewer` for saving 2087 2088 Level: advanced 2089 2090 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2091 @*/ 2092 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2093 { 2094 PetscBool ishdf5; 2095 2096 PetscFunctionBegin; 2097 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2098 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2099 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2100 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2101 if (ishdf5) { 2102 #if defined(PETSC_HAVE_HDF5) 2103 IS globalPointNumbering; 2104 PetscViewerFormat format; 2105 2106 PetscCall(PetscViewerGetFormat(viewer, &format)); 2107 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2108 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2109 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2110 PetscCall(ISDestroy(&globalPointNumbering)); 2111 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2112 #else 2113 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2114 #endif 2115 } 2116 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2117 PetscFunctionReturn(PETSC_SUCCESS); 2118 } 2119 2120 /*@ 2121 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2122 2123 Collective 2124 2125 Input Parameters: 2126 + dm - The `DM` that contains the topology on which the section to be saved is defined 2127 . viewer - The `PetscViewer` for saving 2128 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2129 2130 Level: advanced 2131 2132 Notes: 2133 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. 2134 2135 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. 2136 2137 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2138 @*/ 2139 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2140 { 2141 PetscBool ishdf5; 2142 2143 PetscFunctionBegin; 2144 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2145 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2146 if (!sectiondm) sectiondm = dm; 2147 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2148 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2149 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2150 if (ishdf5) { 2151 #if defined(PETSC_HAVE_HDF5) 2152 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2153 #else 2154 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2155 #endif 2156 } 2157 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2158 PetscFunctionReturn(PETSC_SUCCESS); 2159 } 2160 2161 /*@ 2162 DMPlexGlobalVectorView - Saves a global vector 2163 2164 Collective 2165 2166 Input Parameters: 2167 + dm - The `DM` that represents the topology 2168 . viewer - The `PetscViewer` to save data with 2169 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2170 - vec - The global vector to be saved 2171 2172 Level: advanced 2173 2174 Notes: 2175 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. 2176 2177 Calling sequence: 2178 .vb 2179 DMCreate(PETSC_COMM_WORLD, &dm); 2180 DMSetType(dm, DMPLEX); 2181 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2182 DMClone(dm, §iondm); 2183 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2184 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2185 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2186 PetscSectionSetChart(section, pStart, pEnd); 2187 PetscSectionSetUp(section); 2188 DMSetLocalSection(sectiondm, section); 2189 PetscSectionDestroy(§ion); 2190 DMGetGlobalVector(sectiondm, &vec); 2191 PetscObjectSetName((PetscObject)vec, "vec_name"); 2192 DMPlexTopologyView(dm, viewer); 2193 DMPlexSectionView(dm, viewer, sectiondm); 2194 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2195 DMRestoreGlobalVector(sectiondm, &vec); 2196 DMDestroy(§iondm); 2197 DMDestroy(&dm); 2198 .ve 2199 2200 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2201 @*/ 2202 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2203 { 2204 PetscBool ishdf5; 2205 2206 PetscFunctionBegin; 2207 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2208 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2209 if (!sectiondm) sectiondm = dm; 2210 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2211 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2212 /* Check consistency */ 2213 { 2214 PetscSection section; 2215 PetscBool includesConstraints; 2216 PetscInt m, m1; 2217 2218 PetscCall(VecGetLocalSize(vec, &m1)); 2219 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2220 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2221 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2222 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2223 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2224 } 2225 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2226 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2227 if (ishdf5) { 2228 #if defined(PETSC_HAVE_HDF5) 2229 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2230 #else 2231 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2232 #endif 2233 } 2234 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2235 PetscFunctionReturn(PETSC_SUCCESS); 2236 } 2237 2238 /*@ 2239 DMPlexLocalVectorView - Saves a local vector 2240 2241 Collective 2242 2243 Input Parameters: 2244 + dm - The `DM` that represents the topology 2245 . viewer - The `PetscViewer` to save data with 2246 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2247 - vec - The local vector to be saved 2248 2249 Level: advanced 2250 2251 Note: 2252 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. 2253 2254 Calling sequence: 2255 .vb 2256 DMCreate(PETSC_COMM_WORLD, &dm); 2257 DMSetType(dm, DMPLEX); 2258 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2259 DMClone(dm, §iondm); 2260 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2261 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2262 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2263 PetscSectionSetChart(section, pStart, pEnd); 2264 PetscSectionSetUp(section); 2265 DMSetLocalSection(sectiondm, section); 2266 DMGetLocalVector(sectiondm, &vec); 2267 PetscObjectSetName((PetscObject)vec, "vec_name"); 2268 DMPlexTopologyView(dm, viewer); 2269 DMPlexSectionView(dm, viewer, sectiondm); 2270 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2271 DMRestoreLocalVector(sectiondm, &vec); 2272 DMDestroy(§iondm); 2273 DMDestroy(&dm); 2274 .ve 2275 2276 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2277 @*/ 2278 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2279 { 2280 PetscBool ishdf5; 2281 2282 PetscFunctionBegin; 2283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2284 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2285 if (!sectiondm) sectiondm = dm; 2286 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2287 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2288 /* Check consistency */ 2289 { 2290 PetscSection section; 2291 PetscBool includesConstraints; 2292 PetscInt m, m1; 2293 2294 PetscCall(VecGetLocalSize(vec, &m1)); 2295 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2296 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2297 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2298 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2299 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2300 } 2301 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2302 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2303 if (ishdf5) { 2304 #if defined(PETSC_HAVE_HDF5) 2305 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2306 #else 2307 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2308 #endif 2309 } 2310 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2311 PetscFunctionReturn(PETSC_SUCCESS); 2312 } 2313 2314 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2315 { 2316 PetscBool ishdf5; 2317 2318 PetscFunctionBegin; 2319 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2320 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2321 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2322 if (ishdf5) { 2323 #if defined(PETSC_HAVE_HDF5) 2324 PetscViewerFormat format; 2325 PetscCall(PetscViewerGetFormat(viewer, &format)); 2326 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2327 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2328 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2329 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2330 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2331 PetscFunctionReturn(PETSC_SUCCESS); 2332 #else 2333 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2334 #endif 2335 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2336 } 2337 2338 /*@ 2339 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2340 2341 Collective 2342 2343 Input Parameters: 2344 + dm - The `DM` into which the topology is loaded 2345 - viewer - The `PetscViewer` for the saved topology 2346 2347 Output Parameter: 2348 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; `NULL` if unneeded 2349 2350 Level: advanced 2351 2352 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2353 `PetscViewer`, `PetscSF` 2354 @*/ 2355 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2356 { 2357 PetscBool ishdf5; 2358 2359 PetscFunctionBegin; 2360 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2361 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2362 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2363 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2364 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2365 if (ishdf5) { 2366 #if defined(PETSC_HAVE_HDF5) 2367 PetscViewerFormat format; 2368 PetscCall(PetscViewerGetFormat(viewer, &format)); 2369 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2370 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2371 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2372 #else 2373 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2374 #endif 2375 } 2376 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2377 PetscFunctionReturn(PETSC_SUCCESS); 2378 } 2379 2380 /*@ 2381 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2382 2383 Collective 2384 2385 Input Parameters: 2386 + dm - The `DM` into which the coordinates are loaded 2387 . viewer - The `PetscViewer` for the saved coordinates 2388 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2389 2390 Level: advanced 2391 2392 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2393 `PetscSF`, `PetscViewer` 2394 @*/ 2395 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2396 { 2397 PetscBool ishdf5; 2398 2399 PetscFunctionBegin; 2400 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2401 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2402 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2403 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2404 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2405 if (ishdf5) { 2406 #if defined(PETSC_HAVE_HDF5) 2407 PetscViewerFormat format; 2408 PetscCall(PetscViewerGetFormat(viewer, &format)); 2409 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2410 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2411 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2412 #else 2413 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2414 #endif 2415 } 2416 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2417 PetscFunctionReturn(PETSC_SUCCESS); 2418 } 2419 2420 /*@ 2421 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2422 2423 Collective 2424 2425 Input Parameters: 2426 + dm - The `DM` into which the labels are loaded 2427 . viewer - The `PetscViewer` for the saved labels 2428 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2429 2430 Level: advanced 2431 2432 Note: 2433 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2434 2435 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2436 `PetscSF`, `PetscViewer` 2437 @*/ 2438 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2439 { 2440 PetscBool ishdf5; 2441 2442 PetscFunctionBegin; 2443 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2444 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2445 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2446 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2447 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2448 if (ishdf5) { 2449 #if defined(PETSC_HAVE_HDF5) 2450 PetscViewerFormat format; 2451 2452 PetscCall(PetscViewerGetFormat(viewer, &format)); 2453 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2454 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2455 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2456 #else 2457 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2458 #endif 2459 } 2460 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2461 PetscFunctionReturn(PETSC_SUCCESS); 2462 } 2463 2464 /*@ 2465 DMPlexSectionLoad - Loads section into a `DMPLEX` 2466 2467 Collective 2468 2469 Input Parameters: 2470 + dm - The `DM` that represents the topology 2471 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2472 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2473 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2474 2475 Output Parameters: 2476 + 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) 2477 - 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) 2478 2479 Level: advanced 2480 2481 Notes: 2482 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. 2483 2484 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. 2485 2486 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. 2487 2488 Example using 2 processes: 2489 .vb 2490 NX (number of points on dm): 4 2491 sectionA : the on-disk section 2492 vecA : a vector associated with sectionA 2493 sectionB : sectiondm's local section constructed in this function 2494 vecB (local) : a vector associated with sectiondm's local section 2495 vecB (global) : a vector associated with sectiondm's global section 2496 2497 rank 0 rank 1 2498 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2499 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2500 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2501 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2502 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2503 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2504 sectionB->atlasDof : 1 0 1 | 1 3 2505 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2506 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2507 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2508 .ve 2509 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2510 2511 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2512 @*/ 2513 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2514 { 2515 PetscBool ishdf5; 2516 2517 PetscFunctionBegin; 2518 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2519 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2520 if (!sectiondm) sectiondm = dm; 2521 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2522 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2523 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2524 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2525 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2526 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2527 if (ishdf5) { 2528 #if defined(PETSC_HAVE_HDF5) 2529 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2530 #else 2531 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2532 #endif 2533 } 2534 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2535 PetscFunctionReturn(PETSC_SUCCESS); 2536 } 2537 2538 /*@ 2539 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2540 2541 Collective 2542 2543 Input Parameters: 2544 + dm - The `DM` that represents the topology 2545 . viewer - The `PetscViewer` that represents the on-disk vector data 2546 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2547 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2548 - vec - The global vector to set values of 2549 2550 Level: advanced 2551 2552 Notes: 2553 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. 2554 2555 Calling sequence: 2556 .vb 2557 DMCreate(PETSC_COMM_WORLD, &dm); 2558 DMSetType(dm, DMPLEX); 2559 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2560 DMPlexTopologyLoad(dm, viewer, &sfX); 2561 DMClone(dm, §iondm); 2562 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2563 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2564 DMGetGlobalVector(sectiondm, &vec); 2565 PetscObjectSetName((PetscObject)vec, "vec_name"); 2566 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2567 DMRestoreGlobalVector(sectiondm, &vec); 2568 PetscSFDestroy(&gsf); 2569 PetscSFDestroy(&sfX); 2570 DMDestroy(§iondm); 2571 DMDestroy(&dm); 2572 .ve 2573 2574 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2575 `PetscSF`, `PetscViewer` 2576 @*/ 2577 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2578 { 2579 PetscBool ishdf5; 2580 2581 PetscFunctionBegin; 2582 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2583 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2584 if (!sectiondm) sectiondm = dm; 2585 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2586 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2587 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2588 /* Check consistency */ 2589 { 2590 PetscSection section; 2591 PetscBool includesConstraints; 2592 PetscInt m, m1; 2593 2594 PetscCall(VecGetLocalSize(vec, &m1)); 2595 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2596 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2597 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2598 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2599 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2600 } 2601 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2602 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2603 if (ishdf5) { 2604 #if defined(PETSC_HAVE_HDF5) 2605 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2606 #else 2607 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2608 #endif 2609 } 2610 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2611 PetscFunctionReturn(PETSC_SUCCESS); 2612 } 2613 2614 /*@ 2615 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2616 2617 Collective 2618 2619 Input Parameters: 2620 + dm - The `DM` that represents the topology 2621 . viewer - The `PetscViewer` that represents the on-disk vector data 2622 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2623 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2624 - vec - The local vector to set values of 2625 2626 Level: advanced 2627 2628 Notes: 2629 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. 2630 2631 Calling sequence: 2632 .vb 2633 DMCreate(PETSC_COMM_WORLD, &dm); 2634 DMSetType(dm, DMPLEX); 2635 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2636 DMPlexTopologyLoad(dm, viewer, &sfX); 2637 DMClone(dm, §iondm); 2638 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2639 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2640 DMGetLocalVector(sectiondm, &vec); 2641 PetscObjectSetName((PetscObject)vec, "vec_name"); 2642 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2643 DMRestoreLocalVector(sectiondm, &vec); 2644 PetscSFDestroy(&lsf); 2645 PetscSFDestroy(&sfX); 2646 DMDestroy(§iondm); 2647 DMDestroy(&dm); 2648 .ve 2649 2650 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2651 `PetscSF`, `PetscViewer` 2652 @*/ 2653 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2654 { 2655 PetscBool ishdf5; 2656 2657 PetscFunctionBegin; 2658 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2659 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2660 if (!sectiondm) sectiondm = dm; 2661 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2662 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2663 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2664 /* Check consistency */ 2665 { 2666 PetscSection section; 2667 PetscBool includesConstraints; 2668 PetscInt m, m1; 2669 2670 PetscCall(VecGetLocalSize(vec, &m1)); 2671 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2672 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2673 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2674 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2675 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2676 } 2677 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2678 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2679 if (ishdf5) { 2680 #if defined(PETSC_HAVE_HDF5) 2681 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2682 #else 2683 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2684 #endif 2685 } 2686 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2687 PetscFunctionReturn(PETSC_SUCCESS); 2688 } 2689 2690 PetscErrorCode DMDestroy_Plex(DM dm) 2691 { 2692 DM_Plex *mesh = (DM_Plex *)dm->data; 2693 2694 PetscFunctionBegin; 2695 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2696 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2697 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2698 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2699 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2700 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2701 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2702 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2703 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2704 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2705 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2706 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSectionGetDefault_C", NULL)); 2707 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSectionSetDefault_C", NULL)); 2708 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2709 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2710 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2711 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2712 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2713 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2714 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2715 PetscCall(PetscFree(mesh->cones)); 2716 PetscCall(PetscFree(mesh->coneOrientations)); 2717 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2718 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2719 PetscCall(PetscFree(mesh->supports)); 2720 PetscCall(PetscFree(mesh->cellTypes)); 2721 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2722 PetscCall(PetscFree(mesh->tetgenOpts)); 2723 PetscCall(PetscFree(mesh->triangleOpts)); 2724 PetscCall(PetscFree(mesh->transformType)); 2725 PetscCall(PetscFree(mesh->distributionName)); 2726 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2727 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2728 PetscCall(ISDestroy(&mesh->subpointIS)); 2729 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2730 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2731 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2732 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2733 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2734 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2735 PetscCall(ISDestroy(&mesh->anchorIS)); 2736 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2737 PetscCall(PetscFree(mesh->parents)); 2738 PetscCall(PetscFree(mesh->childIDs)); 2739 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2740 PetscCall(PetscFree(mesh->children)); 2741 PetscCall(DMDestroy(&mesh->referenceTree)); 2742 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2743 PetscCall(PetscFree(mesh->neighbors)); 2744 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2745 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2746 PetscCall(PetscFree(mesh)); 2747 PetscFunctionReturn(PETSC_SUCCESS); 2748 } 2749 2750 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2751 { 2752 PetscSection sectionGlobal, sectionLocal; 2753 PetscInt bs = -1, mbs; 2754 PetscInt localSize, localStart = 0; 2755 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2756 MatType mtype; 2757 ISLocalToGlobalMapping ltog; 2758 2759 PetscFunctionBegin; 2760 PetscCall(MatInitializePackage()); 2761 mtype = dm->mattype; 2762 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2763 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2764 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2765 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2766 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2767 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2768 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2769 PetscCall(MatSetType(*J, mtype)); 2770 PetscCall(MatSetFromOptions(*J)); 2771 PetscCall(MatGetBlockSize(*J, &mbs)); 2772 if (mbs > 1) bs = mbs; 2773 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2774 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2775 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2776 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2777 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2778 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2779 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2780 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2781 if (!isShell) { 2782 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2783 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2784 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2785 2786 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2787 2788 PetscCall(PetscCalloc1(localSize, &pblocks)); 2789 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2790 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2791 for (p = pStart; p < pEnd; ++p) { 2792 switch (dm->blocking_type) { 2793 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2794 PetscInt bdof, offset; 2795 2796 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2797 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2798 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2799 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2800 // Signal block concatenation 2801 if (dof - cdof && sectionLocal->blockStarts && !PetscBTLookup(sectionLocal->blockStarts, p)) pblocks[offset - localStart] = -(dof - cdof); 2802 dof = dof < 0 ? -(dof + 1) : dof; 2803 bdof = cdof && (dof - cdof) ? 1 : dof; 2804 if (dof) { 2805 if (bs < 0) { 2806 bs = bdof; 2807 } else if (bs != bdof) { 2808 bs = 1; 2809 } 2810 } 2811 } break; 2812 case DM_BLOCKING_FIELD_NODE: { 2813 for (PetscInt field = 0; field < num_fields; field++) { 2814 PetscInt num_comp, bdof, offset; 2815 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2816 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2817 if (dof < 0) continue; 2818 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2819 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2820 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); 2821 PetscInt num_nodes = dof / num_comp; 2822 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2823 // Handle possibly constant block size (unlikely) 2824 bdof = cdof && (dof - cdof) ? 1 : dof; 2825 if (dof) { 2826 if (bs < 0) { 2827 bs = bdof; 2828 } else if (bs != bdof) { 2829 bs = 1; 2830 } 2831 } 2832 } 2833 } break; 2834 } 2835 } 2836 /* Must have same blocksize on all procs (some might have no points) */ 2837 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2838 bsLocal[1] = bs; 2839 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2840 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2841 else bs = bsMinMax[0]; 2842 bs = PetscMax(1, bs); 2843 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2844 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2845 PetscCall(MatSetBlockSize(*J, bs)); 2846 PetscCall(MatSetUp(*J)); 2847 } else { 2848 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2849 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2850 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2851 } 2852 { // Consolidate blocks 2853 PetscInt nblocks = 0; 2854 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2855 if (pblocks[i] == 0) continue; 2856 // Negative block size indicates the blocks should be concatenated 2857 if (pblocks[i] < 0) { 2858 pblocks[i] = -pblocks[i]; 2859 pblocks[nblocks - 1] += pblocks[i]; 2860 } else { 2861 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2862 } 2863 for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]); 2864 } 2865 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2866 } 2867 PetscCall(PetscFree(pblocks)); 2868 } 2869 PetscCall(MatSetDM(*J, dm)); 2870 PetscFunctionReturn(PETSC_SUCCESS); 2871 } 2872 2873 /*@ 2874 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2875 2876 Not Collective 2877 2878 Input Parameter: 2879 . dm - The `DMPLEX` 2880 2881 Output Parameter: 2882 . subsection - The subdomain section 2883 2884 Level: developer 2885 2886 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2887 @*/ 2888 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2889 { 2890 DM_Plex *mesh = (DM_Plex *)dm->data; 2891 2892 PetscFunctionBegin; 2893 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2894 if (!mesh->subdomainSection) { 2895 PetscSection section; 2896 PetscSF sf; 2897 2898 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2899 PetscCall(DMGetLocalSection(dm, §ion)); 2900 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2901 PetscCall(PetscSFDestroy(&sf)); 2902 } 2903 *subsection = mesh->subdomainSection; 2904 PetscFunctionReturn(PETSC_SUCCESS); 2905 } 2906 2907 /*@ 2908 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2909 2910 Not Collective 2911 2912 Input Parameter: 2913 . dm - The `DMPLEX` 2914 2915 Output Parameters: 2916 + pStart - The first mesh point 2917 - pEnd - The upper bound for mesh points 2918 2919 Level: beginner 2920 2921 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2922 @*/ 2923 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2924 { 2925 DM_Plex *mesh = (DM_Plex *)dm->data; 2926 2927 PetscFunctionBegin; 2928 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2929 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2930 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2931 PetscFunctionReturn(PETSC_SUCCESS); 2932 } 2933 2934 /*@ 2935 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2936 2937 Not Collective 2938 2939 Input Parameters: 2940 + dm - The `DMPLEX` 2941 . pStart - The first mesh point 2942 - pEnd - The upper bound for mesh points 2943 2944 Level: beginner 2945 2946 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2947 @*/ 2948 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2949 { 2950 DM_Plex *mesh = (DM_Plex *)dm->data; 2951 2952 PetscFunctionBegin; 2953 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2954 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2955 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2956 PetscCall(PetscFree(mesh->cellTypes)); 2957 PetscFunctionReturn(PETSC_SUCCESS); 2958 } 2959 2960 /*@ 2961 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2962 2963 Not Collective 2964 2965 Input Parameters: 2966 + dm - The `DMPLEX` 2967 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2968 2969 Output Parameter: 2970 . size - The cone size for point `p` 2971 2972 Level: beginner 2973 2974 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2975 @*/ 2976 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2977 { 2978 DM_Plex *mesh = (DM_Plex *)dm->data; 2979 2980 PetscFunctionBegin; 2981 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2982 PetscAssertPointer(size, 3); 2983 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2984 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2985 PetscFunctionReturn(PETSC_SUCCESS); 2986 } 2987 2988 /*@ 2989 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2990 2991 Not Collective 2992 2993 Input Parameters: 2994 + dm - The `DMPLEX` 2995 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2996 - size - The cone size for point `p` 2997 2998 Level: beginner 2999 3000 Note: 3001 This should be called after `DMPlexSetChart()`. 3002 3003 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3004 @*/ 3005 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3006 { 3007 DM_Plex *mesh = (DM_Plex *)dm->data; 3008 3009 PetscFunctionBegin; 3010 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3011 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3012 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3013 PetscFunctionReturn(PETSC_SUCCESS); 3014 } 3015 3016 /*@C 3017 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3018 3019 Not Collective 3020 3021 Input Parameters: 3022 + dm - The `DMPLEX` 3023 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3024 3025 Output Parameter: 3026 . cone - An array of points which are on the in-edges for point `p` 3027 3028 Level: beginner 3029 3030 Fortran Notes: 3031 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3032 `DMPlexRestoreCone()` is not needed/available in C. 3033 3034 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3035 @*/ 3036 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3037 { 3038 DM_Plex *mesh = (DM_Plex *)dm->data; 3039 PetscInt off; 3040 3041 PetscFunctionBegin; 3042 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3043 PetscAssertPointer(cone, 3); 3044 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3045 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3046 PetscFunctionReturn(PETSC_SUCCESS); 3047 } 3048 3049 /*@C 3050 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3051 3052 Not Collective 3053 3054 Input Parameters: 3055 + dm - The `DMPLEX` 3056 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3057 3058 Output Parameters: 3059 + pConesSection - `PetscSection` describing the layout of `pCones` 3060 - pCones - An array of points which are on the in-edges for the point set `p` 3061 3062 Level: intermediate 3063 3064 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3065 @*/ 3066 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3067 { 3068 PetscSection cs, newcs; 3069 PetscInt *cones; 3070 PetscInt *newarr = NULL; 3071 PetscInt n; 3072 3073 PetscFunctionBegin; 3074 PetscCall(DMPlexGetCones(dm, &cones)); 3075 PetscCall(DMPlexGetConeSection(dm, &cs)); 3076 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3077 if (pConesSection) *pConesSection = newcs; 3078 if (pCones) { 3079 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3080 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3081 } 3082 PetscFunctionReturn(PETSC_SUCCESS); 3083 } 3084 3085 /*@ 3086 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3087 3088 Not Collective 3089 3090 Input Parameters: 3091 + dm - The `DMPLEX` 3092 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3093 3094 Output Parameter: 3095 . expandedPoints - An array of vertices recursively expanded from input points 3096 3097 Level: advanced 3098 3099 Notes: 3100 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3101 3102 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3103 3104 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3105 `DMPlexGetDepth()`, `IS` 3106 @*/ 3107 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3108 { 3109 IS *expandedPointsAll; 3110 PetscInt depth; 3111 3112 PetscFunctionBegin; 3113 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3114 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3115 PetscAssertPointer(expandedPoints, 3); 3116 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3117 *expandedPoints = expandedPointsAll[0]; 3118 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3119 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3120 PetscFunctionReturn(PETSC_SUCCESS); 3121 } 3122 3123 /*@ 3124 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 3125 3126 Not Collective 3127 3128 Input Parameters: 3129 + dm - The `DMPLEX` 3130 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3131 3132 Output Parameters: 3133 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3134 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3135 - sections - (optional) An array of sections which describe mappings from points to their cone points 3136 3137 Level: advanced 3138 3139 Notes: 3140 Like `DMPlexGetConeTuple()` but recursive. 3141 3142 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. 3143 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3144 3145 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\: 3146 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3147 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3148 3149 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3150 `DMPlexGetDepth()`, `PetscSection`, `IS` 3151 @*/ 3152 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3153 { 3154 const PetscInt *arr0 = NULL, *cone = NULL; 3155 PetscInt *arr = NULL, *newarr = NULL; 3156 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3157 IS *expandedPoints_; 3158 PetscSection *sections_; 3159 3160 PetscFunctionBegin; 3161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3162 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3163 if (depth) PetscAssertPointer(depth, 3); 3164 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3165 if (sections) PetscAssertPointer(sections, 5); 3166 PetscCall(ISGetLocalSize(points, &n)); 3167 PetscCall(ISGetIndices(points, &arr0)); 3168 PetscCall(DMPlexGetDepth(dm, &depth_)); 3169 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3170 PetscCall(PetscCalloc1(depth_, §ions_)); 3171 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3172 for (d = depth_ - 1; d >= 0; d--) { 3173 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3174 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3175 for (i = 0; i < n; i++) { 3176 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3177 if (arr[i] >= start && arr[i] < end) { 3178 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3179 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3180 } else { 3181 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3182 } 3183 } 3184 PetscCall(PetscSectionSetUp(sections_[d])); 3185 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3186 PetscCall(PetscMalloc1(newn, &newarr)); 3187 for (i = 0; i < n; i++) { 3188 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3189 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3190 if (cn > 1) { 3191 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3192 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3193 } else { 3194 newarr[co] = arr[i]; 3195 } 3196 } 3197 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3198 arr = newarr; 3199 n = newn; 3200 } 3201 PetscCall(ISRestoreIndices(points, &arr0)); 3202 *depth = depth_; 3203 if (expandedPoints) *expandedPoints = expandedPoints_; 3204 else { 3205 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3206 PetscCall(PetscFree(expandedPoints_)); 3207 } 3208 if (sections) *sections = sections_; 3209 else { 3210 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3211 PetscCall(PetscFree(sections_)); 3212 } 3213 PetscFunctionReturn(PETSC_SUCCESS); 3214 } 3215 3216 /*@ 3217 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3218 3219 Not Collective 3220 3221 Input Parameters: 3222 + dm - The `DMPLEX` 3223 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3224 3225 Output Parameters: 3226 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3227 . expandedPoints - (optional) An array of recursively expanded cones 3228 - sections - (optional) An array of sections which describe mappings from points to their cone points 3229 3230 Level: advanced 3231 3232 Note: 3233 See `DMPlexGetConeRecursive()` 3234 3235 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3236 `DMPlexGetDepth()`, `IS`, `PetscSection` 3237 @*/ 3238 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3239 { 3240 PetscInt d, depth_; 3241 3242 PetscFunctionBegin; 3243 PetscCall(DMPlexGetDepth(dm, &depth_)); 3244 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3245 if (depth) *depth = 0; 3246 if (expandedPoints) { 3247 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3248 PetscCall(PetscFree(*expandedPoints)); 3249 } 3250 if (sections) { 3251 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3252 PetscCall(PetscFree(*sections)); 3253 } 3254 PetscFunctionReturn(PETSC_SUCCESS); 3255 } 3256 3257 /*@ 3258 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 3259 3260 Not Collective 3261 3262 Input Parameters: 3263 + dm - The `DMPLEX` 3264 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3265 - cone - An array of points which are on the in-edges for point `p` 3266 3267 Level: beginner 3268 3269 Note: 3270 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3271 3272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3273 @*/ 3274 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3275 { 3276 DM_Plex *mesh = (DM_Plex *)dm->data; 3277 PetscInt dof, off, c; 3278 3279 PetscFunctionBegin; 3280 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3281 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3282 if (dof) PetscAssertPointer(cone, 3); 3283 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3284 if (PetscDefined(USE_DEBUG)) { 3285 PetscInt pStart, pEnd; 3286 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3287 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); 3288 for (c = 0; c < dof; ++c) { 3289 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); 3290 mesh->cones[off + c] = cone[c]; 3291 } 3292 } else { 3293 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3294 } 3295 PetscFunctionReturn(PETSC_SUCCESS); 3296 } 3297 3298 /*@C 3299 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3300 3301 Not Collective 3302 3303 Input Parameters: 3304 + dm - The `DMPLEX` 3305 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3306 3307 Output Parameter: 3308 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3309 integer giving the prescription for cone traversal. 3310 3311 Level: beginner 3312 3313 Note: 3314 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3315 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3316 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3317 with the identity. 3318 3319 Fortran Notes: 3320 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3321 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3322 3323 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3324 @*/ 3325 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3326 { 3327 DM_Plex *mesh = (DM_Plex *)dm->data; 3328 PetscInt off; 3329 3330 PetscFunctionBegin; 3331 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3332 if (PetscDefined(USE_DEBUG)) { 3333 PetscInt dof; 3334 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3335 if (dof) PetscAssertPointer(coneOrientation, 3); 3336 } 3337 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3338 3339 *coneOrientation = &mesh->coneOrientations[off]; 3340 PetscFunctionReturn(PETSC_SUCCESS); 3341 } 3342 3343 /*@ 3344 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3345 3346 Not Collective 3347 3348 Input Parameters: 3349 + dm - The `DMPLEX` 3350 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3351 - coneOrientation - An array of orientations 3352 3353 Level: beginner 3354 3355 Notes: 3356 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3357 3358 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3359 3360 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3361 @*/ 3362 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3363 { 3364 DM_Plex *mesh = (DM_Plex *)dm->data; 3365 PetscInt pStart, pEnd; 3366 PetscInt dof, off, c; 3367 3368 PetscFunctionBegin; 3369 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3370 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3371 if (dof) PetscAssertPointer(coneOrientation, 3); 3372 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3373 if (PetscDefined(USE_DEBUG)) { 3374 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3375 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); 3376 for (c = 0; c < dof; ++c) { 3377 PetscInt cdof, o = coneOrientation[c]; 3378 3379 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3380 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); 3381 mesh->coneOrientations[off + c] = o; 3382 } 3383 } else { 3384 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3385 } 3386 PetscFunctionReturn(PETSC_SUCCESS); 3387 } 3388 3389 /*@ 3390 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3391 3392 Not Collective 3393 3394 Input Parameters: 3395 + dm - The `DMPLEX` 3396 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3397 . conePos - The local index in the cone where the point should be put 3398 - conePoint - The mesh point to insert 3399 3400 Level: beginner 3401 3402 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3403 @*/ 3404 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3405 { 3406 DM_Plex *mesh = (DM_Plex *)dm->data; 3407 PetscInt pStart, pEnd; 3408 PetscInt dof, off; 3409 3410 PetscFunctionBegin; 3411 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3412 if (PetscDefined(USE_DEBUG)) { 3413 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3414 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); 3415 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); 3416 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3417 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); 3418 } 3419 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3420 mesh->cones[off + conePos] = conePoint; 3421 PetscFunctionReturn(PETSC_SUCCESS); 3422 } 3423 3424 /*@ 3425 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3426 3427 Not Collective 3428 3429 Input Parameters: 3430 + dm - The `DMPLEX` 3431 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3432 . conePos - The local index in the cone where the point should be put 3433 - coneOrientation - The point orientation to insert 3434 3435 Level: beginner 3436 3437 Note: 3438 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3439 3440 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3441 @*/ 3442 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3443 { 3444 DM_Plex *mesh = (DM_Plex *)dm->data; 3445 PetscInt pStart, pEnd; 3446 PetscInt dof, off; 3447 3448 PetscFunctionBegin; 3449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3450 if (PetscDefined(USE_DEBUG)) { 3451 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3452 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); 3453 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3454 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); 3455 } 3456 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3457 mesh->coneOrientations[off + conePos] = coneOrientation; 3458 PetscFunctionReturn(PETSC_SUCCESS); 3459 } 3460 3461 /*@C 3462 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3463 3464 Not collective 3465 3466 Input Parameters: 3467 + dm - The DMPlex 3468 - p - The point, which must lie in the chart set with DMPlexSetChart() 3469 3470 Output Parameters: 3471 + cone - An array of points which are on the in-edges for point `p` 3472 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3473 integer giving the prescription for cone traversal. 3474 3475 Level: beginner 3476 3477 Notes: 3478 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3479 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3480 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3481 with the identity. 3482 3483 Fortran Notes: 3484 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3485 `DMPlexRestoreCone()` is not needed/available in C. 3486 3487 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3488 @*/ 3489 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3490 { 3491 DM_Plex *mesh = (DM_Plex *)dm->data; 3492 3493 PetscFunctionBegin; 3494 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3495 if (mesh->tr) { 3496 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3497 } else { 3498 PetscInt off; 3499 if (PetscDefined(USE_DEBUG)) { 3500 PetscInt dof; 3501 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3502 if (dof) { 3503 if (cone) PetscAssertPointer(cone, 3); 3504 if (ornt) PetscAssertPointer(ornt, 4); 3505 } 3506 } 3507 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3508 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3509 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3510 } 3511 PetscFunctionReturn(PETSC_SUCCESS); 3512 } 3513 3514 /*@C 3515 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3516 3517 Not Collective 3518 3519 Input Parameters: 3520 + dm - The DMPlex 3521 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3522 . cone - An array of points which are on the in-edges for point p 3523 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3524 integer giving the prescription for cone traversal. 3525 3526 Level: beginner 3527 3528 Notes: 3529 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3530 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3531 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3532 with the identity. 3533 3534 Fortran Notes: 3535 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3536 `DMPlexRestoreCone()` is not needed/available in C. 3537 3538 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3539 @*/ 3540 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3541 { 3542 DM_Plex *mesh = (DM_Plex *)dm->data; 3543 3544 PetscFunctionBegin; 3545 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3546 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3547 PetscFunctionReturn(PETSC_SUCCESS); 3548 } 3549 3550 /*@ 3551 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3552 3553 Not Collective 3554 3555 Input Parameters: 3556 + dm - The `DMPLEX` 3557 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3558 3559 Output Parameter: 3560 . size - The support size for point `p` 3561 3562 Level: beginner 3563 3564 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3565 @*/ 3566 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3567 { 3568 DM_Plex *mesh = (DM_Plex *)dm->data; 3569 3570 PetscFunctionBegin; 3571 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3572 PetscAssertPointer(size, 3); 3573 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3574 PetscFunctionReturn(PETSC_SUCCESS); 3575 } 3576 3577 /*@ 3578 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3579 3580 Not Collective 3581 3582 Input Parameters: 3583 + dm - The `DMPLEX` 3584 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3585 - size - The support size for point `p` 3586 3587 Level: beginner 3588 3589 Note: 3590 This should be called after `DMPlexSetChart()`. 3591 3592 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3593 @*/ 3594 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3595 { 3596 DM_Plex *mesh = (DM_Plex *)dm->data; 3597 3598 PetscFunctionBegin; 3599 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3600 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3601 PetscFunctionReturn(PETSC_SUCCESS); 3602 } 3603 3604 /*@C 3605 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3606 3607 Not Collective 3608 3609 Input Parameters: 3610 + dm - The `DMPLEX` 3611 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3612 3613 Output Parameter: 3614 . support - An array of points which are on the out-edges for point `p` 3615 3616 Level: beginner 3617 3618 Fortran Notes: 3619 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3620 `DMPlexRestoreSupport()` is not needed/available in C. 3621 3622 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3623 @*/ 3624 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3625 { 3626 DM_Plex *mesh = (DM_Plex *)dm->data; 3627 PetscInt off; 3628 3629 PetscFunctionBegin; 3630 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3631 PetscAssertPointer(support, 3); 3632 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3633 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3634 PetscFunctionReturn(PETSC_SUCCESS); 3635 } 3636 3637 /*@ 3638 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3639 3640 Not Collective 3641 3642 Input Parameters: 3643 + dm - The `DMPLEX` 3644 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3645 - support - An array of points which are on the out-edges for point `p` 3646 3647 Level: beginner 3648 3649 Note: 3650 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3651 3652 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3653 @*/ 3654 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3655 { 3656 DM_Plex *mesh = (DM_Plex *)dm->data; 3657 PetscInt pStart, pEnd; 3658 PetscInt dof, off, c; 3659 3660 PetscFunctionBegin; 3661 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3662 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3663 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3664 if (dof) PetscAssertPointer(support, 3); 3665 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3666 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); 3667 for (c = 0; c < dof; ++c) { 3668 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); 3669 mesh->supports[off + c] = support[c]; 3670 } 3671 PetscFunctionReturn(PETSC_SUCCESS); 3672 } 3673 3674 /*@ 3675 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3676 3677 Not Collective 3678 3679 Input Parameters: 3680 + dm - The `DMPLEX` 3681 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3682 . supportPos - The local index in the cone where the point should be put 3683 - supportPoint - The mesh point to insert 3684 3685 Level: beginner 3686 3687 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3688 @*/ 3689 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3690 { 3691 DM_Plex *mesh = (DM_Plex *)dm->data; 3692 PetscInt pStart, pEnd; 3693 PetscInt dof, off; 3694 3695 PetscFunctionBegin; 3696 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3697 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3698 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3699 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3700 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); 3701 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); 3702 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); 3703 mesh->supports[off + supportPos] = supportPoint; 3704 PetscFunctionReturn(PETSC_SUCCESS); 3705 } 3706 3707 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3708 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3709 { 3710 switch (ct) { 3711 case DM_POLYTOPE_SEGMENT: 3712 if (o == -1) return -2; 3713 break; 3714 case DM_POLYTOPE_TRIANGLE: 3715 if (o == -3) return -1; 3716 if (o == -2) return -3; 3717 if (o == -1) return -2; 3718 break; 3719 case DM_POLYTOPE_QUADRILATERAL: 3720 if (o == -4) return -2; 3721 if (o == -3) return -1; 3722 if (o == -2) return -4; 3723 if (o == -1) return -3; 3724 break; 3725 default: 3726 return o; 3727 } 3728 return o; 3729 } 3730 3731 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3732 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3733 { 3734 switch (ct) { 3735 case DM_POLYTOPE_SEGMENT: 3736 if ((o == -2) || (o == 1)) return -1; 3737 if (o == -1) return 0; 3738 break; 3739 case DM_POLYTOPE_TRIANGLE: 3740 if (o == -3) return -2; 3741 if (o == -2) return -1; 3742 if (o == -1) return -3; 3743 break; 3744 case DM_POLYTOPE_QUADRILATERAL: 3745 if (o == -4) return -2; 3746 if (o == -3) return -1; 3747 if (o == -2) return -4; 3748 if (o == -1) return -3; 3749 break; 3750 default: 3751 return o; 3752 } 3753 return o; 3754 } 3755 3756 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3757 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3758 { 3759 PetscInt pStart, pEnd, p; 3760 3761 PetscFunctionBegin; 3762 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3763 for (p = pStart; p < pEnd; ++p) { 3764 const PetscInt *cone, *ornt; 3765 PetscInt coneSize, c; 3766 3767 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3768 PetscCall(DMPlexGetCone(dm, p, &cone)); 3769 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3770 for (c = 0; c < coneSize; ++c) { 3771 DMPolytopeType ct; 3772 const PetscInt o = ornt[c]; 3773 3774 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3775 switch (ct) { 3776 case DM_POLYTOPE_SEGMENT: 3777 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3778 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3779 break; 3780 case DM_POLYTOPE_TRIANGLE: 3781 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3782 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3783 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3784 break; 3785 case DM_POLYTOPE_QUADRILATERAL: 3786 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3787 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3788 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3789 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3790 break; 3791 default: 3792 break; 3793 } 3794 } 3795 } 3796 PetscFunctionReturn(PETSC_SUCCESS); 3797 } 3798 3799 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3800 { 3801 DM_Plex *mesh = (DM_Plex *)dm->data; 3802 3803 PetscFunctionBeginHot; 3804 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3805 if (useCone) { 3806 PetscCall(DMPlexGetConeSize(dm, p, size)); 3807 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3808 } else { 3809 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3810 PetscCall(DMPlexGetSupport(dm, p, arr)); 3811 } 3812 } else { 3813 if (useCone) { 3814 const PetscSection s = mesh->coneSection; 3815 const PetscInt ps = p - s->pStart; 3816 const PetscInt off = s->atlasOff[ps]; 3817 3818 *size = s->atlasDof[ps]; 3819 *arr = mesh->cones + off; 3820 *ornt = mesh->coneOrientations + off; 3821 } else { 3822 const PetscSection s = mesh->supportSection; 3823 const PetscInt ps = p - s->pStart; 3824 const PetscInt off = s->atlasOff[ps]; 3825 3826 *size = s->atlasDof[ps]; 3827 *arr = mesh->supports + off; 3828 } 3829 } 3830 PetscFunctionReturn(PETSC_SUCCESS); 3831 } 3832 3833 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3834 { 3835 DM_Plex *mesh = (DM_Plex *)dm->data; 3836 3837 PetscFunctionBeginHot; 3838 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3839 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3840 } 3841 PetscFunctionReturn(PETSC_SUCCESS); 3842 } 3843 3844 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3845 { 3846 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3847 PetscInt *closure; 3848 const PetscInt *tmp = NULL, *tmpO = NULL; 3849 PetscInt off = 0, tmpSize, t; 3850 3851 PetscFunctionBeginHot; 3852 if (ornt) { 3853 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3854 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; 3855 } 3856 if (*points) { 3857 closure = *points; 3858 } else { 3859 PetscInt maxConeSize, maxSupportSize; 3860 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3861 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3862 } 3863 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3864 if (ct == DM_POLYTOPE_UNKNOWN) { 3865 closure[off++] = p; 3866 closure[off++] = 0; 3867 for (t = 0; t < tmpSize; ++t) { 3868 closure[off++] = tmp[t]; 3869 closure[off++] = tmpO ? tmpO[t] : 0; 3870 } 3871 } else { 3872 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3873 3874 /* We assume that cells with a valid type have faces with a valid type */ 3875 closure[off++] = p; 3876 closure[off++] = ornt; 3877 for (t = 0; t < tmpSize; ++t) { 3878 DMPolytopeType ft; 3879 3880 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3881 closure[off++] = tmp[arr[t]]; 3882 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3883 } 3884 } 3885 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3886 if (numPoints) *numPoints = tmpSize + 1; 3887 if (points) *points = closure; 3888 PetscFunctionReturn(PETSC_SUCCESS); 3889 } 3890 3891 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3892 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3893 { 3894 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3895 const PetscInt *cone, *ornt; 3896 PetscInt *pts, *closure = NULL; 3897 DMPolytopeType ft; 3898 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3899 PetscInt dim, coneSize, c, d, clSize, cl; 3900 3901 PetscFunctionBeginHot; 3902 PetscCall(DMGetDimension(dm, &dim)); 3903 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3904 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3905 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3906 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3907 maxSize = PetscMax(coneSeries, supportSeries); 3908 if (*points) { 3909 pts = *points; 3910 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3911 c = 0; 3912 pts[c++] = point; 3913 pts[c++] = o; 3914 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3915 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3916 for (cl = 0; cl < clSize * 2; cl += 2) { 3917 pts[c++] = closure[cl]; 3918 pts[c++] = closure[cl + 1]; 3919 } 3920 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3921 for (cl = 0; cl < clSize * 2; cl += 2) { 3922 pts[c++] = closure[cl]; 3923 pts[c++] = closure[cl + 1]; 3924 } 3925 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3926 for (d = 2; d < coneSize; ++d) { 3927 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3928 pts[c++] = cone[arr[d * 2 + 0]]; 3929 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3930 } 3931 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3932 if (dim >= 3) { 3933 for (d = 2; d < coneSize; ++d) { 3934 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3935 const PetscInt *fcone, *fornt; 3936 PetscInt fconeSize, fc, i; 3937 3938 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3939 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3940 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3941 for (fc = 0; fc < fconeSize; ++fc) { 3942 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3943 const PetscInt co = farr[fc * 2 + 1]; 3944 3945 for (i = 0; i < c; i += 2) 3946 if (pts[i] == cp) break; 3947 if (i == c) { 3948 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3949 pts[c++] = cp; 3950 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3951 } 3952 } 3953 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3954 } 3955 } 3956 *numPoints = c / 2; 3957 *points = pts; 3958 PetscFunctionReturn(PETSC_SUCCESS); 3959 } 3960 3961 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3962 { 3963 DMPolytopeType ct; 3964 PetscInt *closure, *fifo; 3965 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3966 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3967 PetscInt depth, maxSize; 3968 3969 PetscFunctionBeginHot; 3970 PetscCall(DMPlexGetDepth(dm, &depth)); 3971 if (depth == 1) { 3972 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3973 PetscFunctionReturn(PETSC_SUCCESS); 3974 } 3975 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3976 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; 3977 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 3978 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3979 PetscFunctionReturn(PETSC_SUCCESS); 3980 } 3981 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3982 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3983 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3984 maxSize = PetscMax(coneSeries, supportSeries); 3985 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3986 if (*points) { 3987 closure = *points; 3988 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3989 closure[closureSize++] = p; 3990 closure[closureSize++] = ornt; 3991 fifo[fifoSize++] = p; 3992 fifo[fifoSize++] = ornt; 3993 fifo[fifoSize++] = ct; 3994 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3995 while (fifoSize - fifoStart) { 3996 const PetscInt q = fifo[fifoStart++]; 3997 const PetscInt o = fifo[fifoStart++]; 3998 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3999 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4000 const PetscInt *tmp, *tmpO = NULL; 4001 PetscInt tmpSize, t; 4002 4003 if (PetscDefined(USE_DEBUG)) { 4004 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4005 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); 4006 } 4007 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4008 for (t = 0; t < tmpSize; ++t) { 4009 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4010 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4011 const PetscInt cp = tmp[ip]; 4012 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4013 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4014 PetscInt c; 4015 4016 /* Check for duplicate */ 4017 for (c = 0; c < closureSize; c += 2) { 4018 if (closure[c] == cp) break; 4019 } 4020 if (c == closureSize) { 4021 closure[closureSize++] = cp; 4022 closure[closureSize++] = co; 4023 fifo[fifoSize++] = cp; 4024 fifo[fifoSize++] = co; 4025 fifo[fifoSize++] = ct; 4026 } 4027 } 4028 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4029 } 4030 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4031 if (numPoints) *numPoints = closureSize / 2; 4032 if (points) *points = closure; 4033 PetscFunctionReturn(PETSC_SUCCESS); 4034 } 4035 4036 /*@C 4037 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4038 4039 Not Collective 4040 4041 Input Parameters: 4042 + dm - The `DMPLEX` 4043 . p - The mesh point 4044 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4045 4046 Input/Output Parameter: 4047 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4048 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4049 4050 Output Parameter: 4051 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4052 4053 Level: beginner 4054 4055 Note: 4056 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4057 4058 Fortran Notes: 4059 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4060 4061 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4062 @*/ 4063 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4064 { 4065 PetscFunctionBeginHot; 4066 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4067 if (numPoints) PetscAssertPointer(numPoints, 4); 4068 if (points) PetscAssertPointer(points, 5); 4069 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4070 PetscFunctionReturn(PETSC_SUCCESS); 4071 } 4072 4073 /*@C 4074 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4075 4076 Not Collective 4077 4078 Input Parameters: 4079 + dm - The `DMPLEX` 4080 . p - The mesh point 4081 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4082 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4083 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4084 4085 Level: beginner 4086 4087 Note: 4088 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4089 4090 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4091 @*/ 4092 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4093 { 4094 PetscFunctionBeginHot; 4095 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4096 if (numPoints) *numPoints = 0; 4097 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4098 PetscFunctionReturn(PETSC_SUCCESS); 4099 } 4100 4101 /*@ 4102 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4103 4104 Not Collective 4105 4106 Input Parameter: 4107 . dm - The `DMPLEX` 4108 4109 Output Parameters: 4110 + maxConeSize - The maximum number of in-edges 4111 - maxSupportSize - The maximum number of out-edges 4112 4113 Level: beginner 4114 4115 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4116 @*/ 4117 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4118 { 4119 DM_Plex *mesh = (DM_Plex *)dm->data; 4120 4121 PetscFunctionBegin; 4122 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4123 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4124 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4125 PetscFunctionReturn(PETSC_SUCCESS); 4126 } 4127 4128 PetscErrorCode DMSetUp_Plex(DM dm) 4129 { 4130 DM_Plex *mesh = (DM_Plex *)dm->data; 4131 PetscInt size, maxSupportSize; 4132 4133 PetscFunctionBegin; 4134 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4135 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4136 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4137 PetscCall(PetscMalloc1(size, &mesh->cones)); 4138 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4139 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4140 if (maxSupportSize) { 4141 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4142 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4143 PetscCall(PetscMalloc1(size, &mesh->supports)); 4144 } 4145 PetscFunctionReturn(PETSC_SUCCESS); 4146 } 4147 4148 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4149 { 4150 PetscFunctionBegin; 4151 if (subdm) PetscCall(DMClone(dm, subdm)); 4152 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 4153 if (subdm) (*subdm)->useNatural = dm->useNatural; 4154 if (dm->useNatural && dm->sfMigration) { 4155 PetscSF sfNatural; 4156 4157 (*subdm)->sfMigration = dm->sfMigration; 4158 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4159 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4160 (*subdm)->sfNatural = sfNatural; 4161 } 4162 PetscFunctionReturn(PETSC_SUCCESS); 4163 } 4164 4165 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4166 { 4167 PetscInt i = 0; 4168 4169 PetscFunctionBegin; 4170 PetscCall(DMClone(dms[0], superdm)); 4171 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4172 (*superdm)->useNatural = PETSC_FALSE; 4173 for (i = 0; i < len; i++) { 4174 if (dms[i]->useNatural && dms[i]->sfMigration) { 4175 PetscSF sfNatural; 4176 4177 (*superdm)->sfMigration = dms[i]->sfMigration; 4178 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4179 (*superdm)->useNatural = PETSC_TRUE; 4180 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4181 (*superdm)->sfNatural = sfNatural; 4182 break; 4183 } 4184 } 4185 PetscFunctionReturn(PETSC_SUCCESS); 4186 } 4187 4188 /*@ 4189 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4190 4191 Not Collective 4192 4193 Input Parameter: 4194 . dm - The `DMPLEX` 4195 4196 Level: beginner 4197 4198 Note: 4199 This should be called after all calls to `DMPlexSetCone()` 4200 4201 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4202 @*/ 4203 PetscErrorCode DMPlexSymmetrize(DM dm) 4204 { 4205 DM_Plex *mesh = (DM_Plex *)dm->data; 4206 PetscInt *offsets; 4207 PetscInt supportSize; 4208 PetscInt pStart, pEnd, p; 4209 4210 PetscFunctionBegin; 4211 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4212 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4213 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4214 /* Calculate support sizes */ 4215 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4216 for (p = pStart; p < pEnd; ++p) { 4217 PetscInt dof, off, c; 4218 4219 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4220 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4221 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4222 } 4223 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4224 /* Calculate supports */ 4225 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4226 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4227 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4228 for (p = pStart; p < pEnd; ++p) { 4229 PetscInt dof, off, c; 4230 4231 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4232 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4233 for (c = off; c < off + dof; ++c) { 4234 const PetscInt q = mesh->cones[c]; 4235 PetscInt offS; 4236 4237 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4238 4239 mesh->supports[offS + offsets[q]] = p; 4240 ++offsets[q]; 4241 } 4242 } 4243 PetscCall(PetscFree(offsets)); 4244 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4245 PetscFunctionReturn(PETSC_SUCCESS); 4246 } 4247 4248 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4249 { 4250 IS stratumIS; 4251 4252 PetscFunctionBegin; 4253 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4254 if (PetscDefined(USE_DEBUG)) { 4255 PetscInt qStart, qEnd, numLevels, level; 4256 PetscBool overlap = PETSC_FALSE; 4257 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4258 for (level = 0; level < numLevels; level++) { 4259 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4260 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4261 overlap = PETSC_TRUE; 4262 break; 4263 } 4264 } 4265 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); 4266 } 4267 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4268 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4269 PetscCall(ISDestroy(&stratumIS)); 4270 PetscFunctionReturn(PETSC_SUCCESS); 4271 } 4272 4273 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4274 { 4275 PetscInt *pMin, *pMax; 4276 PetscInt pStart, pEnd; 4277 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4278 4279 PetscFunctionBegin; 4280 { 4281 DMLabel label2; 4282 4283 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4284 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4285 } 4286 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4287 for (PetscInt p = pStart; p < pEnd; ++p) { 4288 DMPolytopeType ct; 4289 4290 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4291 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4292 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4293 } 4294 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4295 for (PetscInt d = dmin; d <= dmax; ++d) { 4296 pMin[d] = PETSC_MAX_INT; 4297 pMax[d] = PETSC_MIN_INT; 4298 } 4299 for (PetscInt p = pStart; p < pEnd; ++p) { 4300 DMPolytopeType ct; 4301 PetscInt d; 4302 4303 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4304 d = DMPolytopeTypeGetDim(ct); 4305 pMin[d] = PetscMin(p, pMin[d]); 4306 pMax[d] = PetscMax(p, pMax[d]); 4307 } 4308 for (PetscInt d = dmin; d <= dmax; ++d) { 4309 if (pMin[d] > pMax[d]) continue; 4310 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4311 } 4312 PetscCall(PetscFree2(pMin, pMax)); 4313 PetscFunctionReturn(PETSC_SUCCESS); 4314 } 4315 4316 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4317 { 4318 PetscInt pStart, pEnd; 4319 PetscInt numRoots = 0, numLeaves = 0; 4320 4321 PetscFunctionBegin; 4322 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4323 { 4324 /* Initialize roots and count leaves */ 4325 PetscInt sMin = PETSC_MAX_INT; 4326 PetscInt sMax = PETSC_MIN_INT; 4327 PetscInt coneSize, supportSize; 4328 4329 for (PetscInt p = pStart; p < pEnd; ++p) { 4330 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4331 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4332 if (!coneSize && supportSize) { 4333 sMin = PetscMin(p, sMin); 4334 sMax = PetscMax(p, sMax); 4335 ++numRoots; 4336 } else if (!supportSize && coneSize) { 4337 ++numLeaves; 4338 } else if (!supportSize && !coneSize) { 4339 /* Isolated points */ 4340 sMin = PetscMin(p, sMin); 4341 sMax = PetscMax(p, sMax); 4342 } 4343 } 4344 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4345 } 4346 4347 if (numRoots + numLeaves == (pEnd - pStart)) { 4348 PetscInt sMin = PETSC_MAX_INT; 4349 PetscInt sMax = PETSC_MIN_INT; 4350 PetscInt coneSize, supportSize; 4351 4352 for (PetscInt p = pStart; p < pEnd; ++p) { 4353 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4354 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4355 if (!supportSize && coneSize) { 4356 sMin = PetscMin(p, sMin); 4357 sMax = PetscMax(p, sMax); 4358 } 4359 } 4360 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4361 } else { 4362 PetscInt level = 0; 4363 PetscInt qStart, qEnd; 4364 4365 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4366 while (qEnd > qStart) { 4367 PetscInt sMin = PETSC_MAX_INT; 4368 PetscInt sMax = PETSC_MIN_INT; 4369 4370 for (PetscInt q = qStart; q < qEnd; ++q) { 4371 const PetscInt *support; 4372 PetscInt supportSize; 4373 4374 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4375 PetscCall(DMPlexGetSupport(dm, q, &support)); 4376 for (PetscInt s = 0; s < supportSize; ++s) { 4377 sMin = PetscMin(support[s], sMin); 4378 sMax = PetscMax(support[s], sMax); 4379 } 4380 } 4381 PetscCall(DMLabelGetNumValues(label, &level)); 4382 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4383 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4384 } 4385 } 4386 PetscFunctionReturn(PETSC_SUCCESS); 4387 } 4388 4389 /*@ 4390 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4391 4392 Collective 4393 4394 Input Parameter: 4395 . dm - The `DMPLEX` 4396 4397 Level: beginner 4398 4399 Notes: 4400 The strata group all points of the same grade, and this function calculates the strata. This 4401 grade can be seen as the height (or depth) of the point in the DAG. 4402 4403 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4404 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4405 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4406 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4407 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4408 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4409 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4410 4411 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4412 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4413 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 4414 to interpolate only that one (e0), so that 4415 .vb 4416 cone(c0) = {e0, v2} 4417 cone(e0) = {v0, v1} 4418 .ve 4419 If `DMPlexStratify()` is run on this mesh, it will give depths 4420 .vb 4421 depth 0 = {v0, v1, v2} 4422 depth 1 = {e0, c0} 4423 .ve 4424 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4425 4426 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4427 4428 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4429 @*/ 4430 PetscErrorCode DMPlexStratify(DM dm) 4431 { 4432 DM_Plex *mesh = (DM_Plex *)dm->data; 4433 DMLabel label; 4434 PetscBool flg = PETSC_FALSE; 4435 4436 PetscFunctionBegin; 4437 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4438 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4439 4440 // Create depth label 4441 PetscCall(DMCreateLabel(dm, "depth")); 4442 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4443 4444 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4445 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4446 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4447 4448 { /* just in case there is an empty process */ 4449 PetscInt numValues, maxValues = 0, v; 4450 4451 PetscCall(DMLabelGetNumValues(label, &numValues)); 4452 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4453 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4454 } 4455 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4456 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4457 PetscFunctionReturn(PETSC_SUCCESS); 4458 } 4459 4460 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4461 { 4462 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4463 PetscInt dim, depth, pheight, coneSize; 4464 4465 PetscFunctionBeginHot; 4466 PetscCall(DMGetDimension(dm, &dim)); 4467 PetscCall(DMPlexGetDepth(dm, &depth)); 4468 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4469 pheight = depth - pdepth; 4470 if (depth <= 1) { 4471 switch (pdepth) { 4472 case 0: 4473 ct = DM_POLYTOPE_POINT; 4474 break; 4475 case 1: 4476 switch (coneSize) { 4477 case 2: 4478 ct = DM_POLYTOPE_SEGMENT; 4479 break; 4480 case 3: 4481 ct = DM_POLYTOPE_TRIANGLE; 4482 break; 4483 case 4: 4484 switch (dim) { 4485 case 2: 4486 ct = DM_POLYTOPE_QUADRILATERAL; 4487 break; 4488 case 3: 4489 ct = DM_POLYTOPE_TETRAHEDRON; 4490 break; 4491 default: 4492 break; 4493 } 4494 break; 4495 case 5: 4496 ct = DM_POLYTOPE_PYRAMID; 4497 break; 4498 case 6: 4499 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4500 break; 4501 case 8: 4502 ct = DM_POLYTOPE_HEXAHEDRON; 4503 break; 4504 default: 4505 break; 4506 } 4507 } 4508 } else { 4509 if (pdepth == 0) { 4510 ct = DM_POLYTOPE_POINT; 4511 } else if (pheight == 0) { 4512 switch (dim) { 4513 case 1: 4514 switch (coneSize) { 4515 case 2: 4516 ct = DM_POLYTOPE_SEGMENT; 4517 break; 4518 default: 4519 break; 4520 } 4521 break; 4522 case 2: 4523 switch (coneSize) { 4524 case 3: 4525 ct = DM_POLYTOPE_TRIANGLE; 4526 break; 4527 case 4: 4528 ct = DM_POLYTOPE_QUADRILATERAL; 4529 break; 4530 default: 4531 break; 4532 } 4533 break; 4534 case 3: 4535 switch (coneSize) { 4536 case 4: 4537 ct = DM_POLYTOPE_TETRAHEDRON; 4538 break; 4539 case 5: { 4540 const PetscInt *cone; 4541 PetscInt faceConeSize; 4542 4543 PetscCall(DMPlexGetCone(dm, p, &cone)); 4544 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4545 switch (faceConeSize) { 4546 case 3: 4547 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4548 break; 4549 case 4: 4550 ct = DM_POLYTOPE_PYRAMID; 4551 break; 4552 } 4553 } break; 4554 case 6: 4555 ct = DM_POLYTOPE_HEXAHEDRON; 4556 break; 4557 default: 4558 break; 4559 } 4560 break; 4561 default: 4562 break; 4563 } 4564 } else if (pheight > 0) { 4565 switch (coneSize) { 4566 case 2: 4567 ct = DM_POLYTOPE_SEGMENT; 4568 break; 4569 case 3: 4570 ct = DM_POLYTOPE_TRIANGLE; 4571 break; 4572 case 4: 4573 ct = DM_POLYTOPE_QUADRILATERAL; 4574 break; 4575 default: 4576 break; 4577 } 4578 } 4579 } 4580 *pt = ct; 4581 PetscFunctionReturn(PETSC_SUCCESS); 4582 } 4583 4584 /*@ 4585 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4586 4587 Collective 4588 4589 Input Parameter: 4590 . dm - The `DMPLEX` 4591 4592 Level: developer 4593 4594 Note: 4595 This function is normally called automatically when a cell type is requested. It creates an 4596 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4597 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4598 4599 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4600 4601 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4602 @*/ 4603 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4604 { 4605 DM_Plex *mesh; 4606 DMLabel ctLabel; 4607 PetscInt pStart, pEnd, p; 4608 4609 PetscFunctionBegin; 4610 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4611 mesh = (DM_Plex *)dm->data; 4612 PetscCall(DMCreateLabel(dm, "celltype")); 4613 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4614 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4615 PetscCall(PetscFree(mesh->cellTypes)); 4616 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4617 for (p = pStart; p < pEnd; ++p) { 4618 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4619 PetscInt pdepth; 4620 4621 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4622 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4623 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4624 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4625 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4626 } 4627 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4628 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4629 PetscFunctionReturn(PETSC_SUCCESS); 4630 } 4631 4632 /*@C 4633 DMPlexGetJoin - Get an array for the join of the set of points 4634 4635 Not Collective 4636 4637 Input Parameters: 4638 + dm - The `DMPLEX` object 4639 . numPoints - The number of input points for the join 4640 - points - The input points 4641 4642 Output Parameters: 4643 + numCoveredPoints - The number of points in the join 4644 - coveredPoints - The points in the join 4645 4646 Level: intermediate 4647 4648 Note: 4649 Currently, this is restricted to a single level join 4650 4651 Fortran Notes: 4652 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4653 4654 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4655 @*/ 4656 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4657 { 4658 DM_Plex *mesh = (DM_Plex *)dm->data; 4659 PetscInt *join[2]; 4660 PetscInt joinSize, i = 0; 4661 PetscInt dof, off, p, c, m; 4662 PetscInt maxSupportSize; 4663 4664 PetscFunctionBegin; 4665 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4666 PetscAssertPointer(points, 3); 4667 PetscAssertPointer(numCoveredPoints, 4); 4668 PetscAssertPointer(coveredPoints, 5); 4669 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4670 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4671 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4672 /* Copy in support of first point */ 4673 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4674 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4675 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4676 /* Check each successive support */ 4677 for (p = 1; p < numPoints; ++p) { 4678 PetscInt newJoinSize = 0; 4679 4680 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4681 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4682 for (c = 0; c < dof; ++c) { 4683 const PetscInt point = mesh->supports[off + c]; 4684 4685 for (m = 0; m < joinSize; ++m) { 4686 if (point == join[i][m]) { 4687 join[1 - i][newJoinSize++] = point; 4688 break; 4689 } 4690 } 4691 } 4692 joinSize = newJoinSize; 4693 i = 1 - i; 4694 } 4695 *numCoveredPoints = joinSize; 4696 *coveredPoints = join[i]; 4697 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4698 PetscFunctionReturn(PETSC_SUCCESS); 4699 } 4700 4701 /*@C 4702 DMPlexRestoreJoin - Restore 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 Fortran Notes: 4718 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4719 4720 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4721 @*/ 4722 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4723 { 4724 PetscFunctionBegin; 4725 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4726 if (points) PetscAssertPointer(points, 3); 4727 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4728 PetscAssertPointer(coveredPoints, 5); 4729 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4730 if (numCoveredPoints) *numCoveredPoints = 0; 4731 PetscFunctionReturn(PETSC_SUCCESS); 4732 } 4733 4734 /*@C 4735 DMPlexGetFullJoin - Get an array for the join of the set of points 4736 4737 Not Collective 4738 4739 Input Parameters: 4740 + dm - The `DMPLEX` object 4741 . numPoints - The number of input points for the join 4742 - points - The input points 4743 4744 Output Parameters: 4745 + numCoveredPoints - The number of points in the join 4746 - coveredPoints - The points in the join 4747 4748 Level: intermediate 4749 4750 Fortran Notes: 4751 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4752 4753 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4754 @*/ 4755 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4756 { 4757 PetscInt *offsets, **closures; 4758 PetscInt *join[2]; 4759 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4760 PetscInt p, d, c, m, ms; 4761 4762 PetscFunctionBegin; 4763 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4764 PetscAssertPointer(points, 3); 4765 PetscAssertPointer(numCoveredPoints, 4); 4766 PetscAssertPointer(coveredPoints, 5); 4767 4768 PetscCall(DMPlexGetDepth(dm, &depth)); 4769 PetscCall(PetscCalloc1(numPoints, &closures)); 4770 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4771 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4772 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4773 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4774 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4775 4776 for (p = 0; p < numPoints; ++p) { 4777 PetscInt closureSize; 4778 4779 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4780 4781 offsets[p * (depth + 2) + 0] = 0; 4782 for (d = 0; d < depth + 1; ++d) { 4783 PetscInt pStart, pEnd, i; 4784 4785 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4786 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4787 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4788 offsets[p * (depth + 2) + d + 1] = i; 4789 break; 4790 } 4791 } 4792 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4793 } 4794 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); 4795 } 4796 for (d = 0; d < depth + 1; ++d) { 4797 PetscInt dof; 4798 4799 /* Copy in support of first point */ 4800 dof = offsets[d + 1] - offsets[d]; 4801 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4802 /* Check each successive cone */ 4803 for (p = 1; p < numPoints && joinSize; ++p) { 4804 PetscInt newJoinSize = 0; 4805 4806 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4807 for (c = 0; c < dof; ++c) { 4808 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4809 4810 for (m = 0; m < joinSize; ++m) { 4811 if (point == join[i][m]) { 4812 join[1 - i][newJoinSize++] = point; 4813 break; 4814 } 4815 } 4816 } 4817 joinSize = newJoinSize; 4818 i = 1 - i; 4819 } 4820 if (joinSize) break; 4821 } 4822 *numCoveredPoints = joinSize; 4823 *coveredPoints = join[i]; 4824 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4825 PetscCall(PetscFree(closures)); 4826 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4827 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4828 PetscFunctionReturn(PETSC_SUCCESS); 4829 } 4830 4831 /*@C 4832 DMPlexGetMeet - Get an array for the meet of the set of points 4833 4834 Not Collective 4835 4836 Input Parameters: 4837 + dm - The `DMPLEX` object 4838 . numPoints - The number of input points for the meet 4839 - points - The input points 4840 4841 Output Parameters: 4842 + numCoveringPoints - The number of points in the meet 4843 - coveringPoints - The points in the meet 4844 4845 Level: intermediate 4846 4847 Note: 4848 Currently, this is restricted to a single level meet 4849 4850 Fortran Notes: 4851 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4852 4853 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4854 @*/ 4855 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4856 { 4857 DM_Plex *mesh = (DM_Plex *)dm->data; 4858 PetscInt *meet[2]; 4859 PetscInt meetSize, i = 0; 4860 PetscInt dof, off, p, c, m; 4861 PetscInt maxConeSize; 4862 4863 PetscFunctionBegin; 4864 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4865 PetscAssertPointer(points, 3); 4866 PetscAssertPointer(numCoveringPoints, 4); 4867 PetscAssertPointer(coveringPoints, 5); 4868 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4869 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4870 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4871 /* Copy in cone of first point */ 4872 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4873 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4874 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4875 /* Check each successive cone */ 4876 for (p = 1; p < numPoints; ++p) { 4877 PetscInt newMeetSize = 0; 4878 4879 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4880 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4881 for (c = 0; c < dof; ++c) { 4882 const PetscInt point = mesh->cones[off + c]; 4883 4884 for (m = 0; m < meetSize; ++m) { 4885 if (point == meet[i][m]) { 4886 meet[1 - i][newMeetSize++] = point; 4887 break; 4888 } 4889 } 4890 } 4891 meetSize = newMeetSize; 4892 i = 1 - i; 4893 } 4894 *numCoveringPoints = meetSize; 4895 *coveringPoints = meet[i]; 4896 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4897 PetscFunctionReturn(PETSC_SUCCESS); 4898 } 4899 4900 /*@C 4901 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4902 4903 Not Collective 4904 4905 Input Parameters: 4906 + dm - The `DMPLEX` object 4907 . numPoints - The number of input points for the meet 4908 - points - The input points 4909 4910 Output Parameters: 4911 + numCoveredPoints - The number of points in the meet 4912 - coveredPoints - The points in the meet 4913 4914 Level: intermediate 4915 4916 Fortran Notes: 4917 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4918 4919 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4920 @*/ 4921 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4922 { 4923 PetscFunctionBegin; 4924 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4925 if (points) PetscAssertPointer(points, 3); 4926 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4927 PetscAssertPointer(coveredPoints, 5); 4928 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4929 if (numCoveredPoints) *numCoveredPoints = 0; 4930 PetscFunctionReturn(PETSC_SUCCESS); 4931 } 4932 4933 /*@C 4934 DMPlexGetFullMeet - Get an array for the meet of the set of points 4935 4936 Not Collective 4937 4938 Input Parameters: 4939 + dm - The `DMPLEX` object 4940 . numPoints - The number of input points for the meet 4941 - points - The input points 4942 4943 Output Parameters: 4944 + numCoveredPoints - The number of points in the meet 4945 - coveredPoints - The points in the meet 4946 4947 Level: intermediate 4948 4949 Fortran Notes: 4950 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4951 4952 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4953 @*/ 4954 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4955 { 4956 PetscInt *offsets, **closures; 4957 PetscInt *meet[2]; 4958 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4959 PetscInt p, h, c, m, mc; 4960 4961 PetscFunctionBegin; 4962 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4963 PetscAssertPointer(points, 3); 4964 PetscAssertPointer(numCoveredPoints, 4); 4965 PetscAssertPointer(coveredPoints, 5); 4966 4967 PetscCall(DMPlexGetDepth(dm, &height)); 4968 PetscCall(PetscMalloc1(numPoints, &closures)); 4969 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4970 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4971 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4972 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4973 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4974 4975 for (p = 0; p < numPoints; ++p) { 4976 PetscInt closureSize; 4977 4978 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4979 4980 offsets[p * (height + 2) + 0] = 0; 4981 for (h = 0; h < height + 1; ++h) { 4982 PetscInt pStart, pEnd, i; 4983 4984 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4985 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4986 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4987 offsets[p * (height + 2) + h + 1] = i; 4988 break; 4989 } 4990 } 4991 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4992 } 4993 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); 4994 } 4995 for (h = 0; h < height + 1; ++h) { 4996 PetscInt dof; 4997 4998 /* Copy in cone of first point */ 4999 dof = offsets[h + 1] - offsets[h]; 5000 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5001 /* Check each successive cone */ 5002 for (p = 1; p < numPoints && meetSize; ++p) { 5003 PetscInt newMeetSize = 0; 5004 5005 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5006 for (c = 0; c < dof; ++c) { 5007 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5008 5009 for (m = 0; m < meetSize; ++m) { 5010 if (point == meet[i][m]) { 5011 meet[1 - i][newMeetSize++] = point; 5012 break; 5013 } 5014 } 5015 } 5016 meetSize = newMeetSize; 5017 i = 1 - i; 5018 } 5019 if (meetSize) break; 5020 } 5021 *numCoveredPoints = meetSize; 5022 *coveredPoints = meet[i]; 5023 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5024 PetscCall(PetscFree(closures)); 5025 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5026 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5027 PetscFunctionReturn(PETSC_SUCCESS); 5028 } 5029 5030 /*@C 5031 DMPlexEqual - Determine if two `DM` have the same topology 5032 5033 Not Collective 5034 5035 Input Parameters: 5036 + dmA - A `DMPLEX` object 5037 - dmB - A `DMPLEX` object 5038 5039 Output Parameter: 5040 . equal - `PETSC_TRUE` if the topologies are identical 5041 5042 Level: intermediate 5043 5044 Note: 5045 We are not solving graph isomorphism, so we do not permute. 5046 5047 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5048 @*/ 5049 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5050 { 5051 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5052 5053 PetscFunctionBegin; 5054 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5055 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5056 PetscAssertPointer(equal, 3); 5057 5058 *equal = PETSC_FALSE; 5059 PetscCall(DMPlexGetDepth(dmA, &depth)); 5060 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5061 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5062 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5063 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5064 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5065 for (p = pStart; p < pEnd; ++p) { 5066 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5067 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5068 5069 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5070 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5071 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5072 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5073 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5074 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5075 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5076 for (c = 0; c < coneSize; ++c) { 5077 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5078 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5079 } 5080 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5081 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5082 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5083 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5084 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5085 for (s = 0; s < supportSize; ++s) { 5086 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5087 } 5088 } 5089 *equal = PETSC_TRUE; 5090 PetscFunctionReturn(PETSC_SUCCESS); 5091 } 5092 5093 /*@C 5094 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5095 5096 Not Collective 5097 5098 Input Parameters: 5099 + dm - The `DMPLEX` 5100 . cellDim - The cell dimension 5101 - numCorners - The number of vertices on a cell 5102 5103 Output Parameter: 5104 . numFaceVertices - The number of vertices on a face 5105 5106 Level: developer 5107 5108 Note: 5109 Of course this can only work for a restricted set of symmetric shapes 5110 5111 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5112 @*/ 5113 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5114 { 5115 MPI_Comm comm; 5116 5117 PetscFunctionBegin; 5118 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5119 PetscAssertPointer(numFaceVertices, 4); 5120 switch (cellDim) { 5121 case 0: 5122 *numFaceVertices = 0; 5123 break; 5124 case 1: 5125 *numFaceVertices = 1; 5126 break; 5127 case 2: 5128 switch (numCorners) { 5129 case 3: /* triangle */ 5130 *numFaceVertices = 2; /* Edge has 2 vertices */ 5131 break; 5132 case 4: /* quadrilateral */ 5133 *numFaceVertices = 2; /* Edge has 2 vertices */ 5134 break; 5135 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5136 *numFaceVertices = 3; /* Edge has 3 vertices */ 5137 break; 5138 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5139 *numFaceVertices = 3; /* Edge has 3 vertices */ 5140 break; 5141 default: 5142 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5143 } 5144 break; 5145 case 3: 5146 switch (numCorners) { 5147 case 4: /* tetradehdron */ 5148 *numFaceVertices = 3; /* Face has 3 vertices */ 5149 break; 5150 case 6: /* tet cohesive cells */ 5151 *numFaceVertices = 4; /* Face has 4 vertices */ 5152 break; 5153 case 8: /* hexahedron */ 5154 *numFaceVertices = 4; /* Face has 4 vertices */ 5155 break; 5156 case 9: /* tet cohesive Lagrange cells */ 5157 *numFaceVertices = 6; /* Face has 6 vertices */ 5158 break; 5159 case 10: /* quadratic tetrahedron */ 5160 *numFaceVertices = 6; /* Face has 6 vertices */ 5161 break; 5162 case 12: /* hex cohesive Lagrange cells */ 5163 *numFaceVertices = 6; /* Face has 6 vertices */ 5164 break; 5165 case 18: /* quadratic tet cohesive Lagrange cells */ 5166 *numFaceVertices = 6; /* Face has 6 vertices */ 5167 break; 5168 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5169 *numFaceVertices = 9; /* Face has 9 vertices */ 5170 break; 5171 default: 5172 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5173 } 5174 break; 5175 default: 5176 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5177 } 5178 PetscFunctionReturn(PETSC_SUCCESS); 5179 } 5180 5181 /*@ 5182 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5183 5184 Not Collective 5185 5186 Input Parameter: 5187 . dm - The `DMPLEX` object 5188 5189 Output Parameter: 5190 . depthLabel - The `DMLabel` recording point depth 5191 5192 Level: developer 5193 5194 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5195 @*/ 5196 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5197 { 5198 PetscFunctionBegin; 5199 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5200 PetscAssertPointer(depthLabel, 2); 5201 *depthLabel = dm->depthLabel; 5202 PetscFunctionReturn(PETSC_SUCCESS); 5203 } 5204 5205 /*@ 5206 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5207 5208 Not Collective 5209 5210 Input Parameter: 5211 . dm - The `DMPLEX` object 5212 5213 Output Parameter: 5214 . depth - The number of strata (breadth first levels) in the DAG 5215 5216 Level: developer 5217 5218 Notes: 5219 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5220 5221 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5222 5223 An empty mesh gives -1. 5224 5225 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5226 @*/ 5227 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5228 { 5229 DM_Plex *mesh = (DM_Plex *)dm->data; 5230 DMLabel label; 5231 PetscInt d = 0; 5232 5233 PetscFunctionBegin; 5234 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5235 PetscAssertPointer(depth, 2); 5236 if (mesh->tr) { 5237 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5238 } else { 5239 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5240 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 5241 *depth = d - 1; 5242 } 5243 PetscFunctionReturn(PETSC_SUCCESS); 5244 } 5245 5246 /*@ 5247 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5248 5249 Not Collective 5250 5251 Input Parameters: 5252 + dm - The `DMPLEX` object 5253 - depth - The requested depth 5254 5255 Output Parameters: 5256 + start - The first point at this `depth` 5257 - end - One beyond the last point at this `depth` 5258 5259 Level: developer 5260 5261 Notes: 5262 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5263 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5264 higher dimension, e.g., "edges". 5265 5266 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5267 @*/ 5268 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5269 { 5270 DM_Plex *mesh = (DM_Plex *)dm->data; 5271 DMLabel label; 5272 PetscInt pStart, pEnd; 5273 5274 PetscFunctionBegin; 5275 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5276 if (start) { 5277 PetscAssertPointer(start, 3); 5278 *start = 0; 5279 } 5280 if (end) { 5281 PetscAssertPointer(end, 4); 5282 *end = 0; 5283 } 5284 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5285 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5286 if (depth < 0) { 5287 if (start) *start = pStart; 5288 if (end) *end = pEnd; 5289 PetscFunctionReturn(PETSC_SUCCESS); 5290 } 5291 if (mesh->tr) { 5292 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5293 } else { 5294 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5295 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5296 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5297 } 5298 PetscFunctionReturn(PETSC_SUCCESS); 5299 } 5300 5301 /*@ 5302 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5303 5304 Not Collective 5305 5306 Input Parameters: 5307 + dm - The `DMPLEX` object 5308 - height - The requested height 5309 5310 Output Parameters: 5311 + start - The first point at this `height` 5312 - end - One beyond the last point at this `height` 5313 5314 Level: developer 5315 5316 Notes: 5317 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5318 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5319 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5320 5321 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5322 @*/ 5323 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5324 { 5325 DMLabel label; 5326 PetscInt depth, pStart, pEnd; 5327 5328 PetscFunctionBegin; 5329 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5330 if (start) { 5331 PetscAssertPointer(start, 3); 5332 *start = 0; 5333 } 5334 if (end) { 5335 PetscAssertPointer(end, 4); 5336 *end = 0; 5337 } 5338 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5339 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5340 if (height < 0) { 5341 if (start) *start = pStart; 5342 if (end) *end = pEnd; 5343 PetscFunctionReturn(PETSC_SUCCESS); 5344 } 5345 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5346 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5347 else PetscCall(DMGetDimension(dm, &depth)); 5348 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5349 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5350 PetscFunctionReturn(PETSC_SUCCESS); 5351 } 5352 5353 /*@ 5354 DMPlexGetPointDepth - Get the `depth` of a given point 5355 5356 Not Collective 5357 5358 Input Parameters: 5359 + dm - The `DMPLEX` object 5360 - point - The point 5361 5362 Output Parameter: 5363 . depth - The depth of the `point` 5364 5365 Level: intermediate 5366 5367 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5368 @*/ 5369 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5370 { 5371 PetscFunctionBegin; 5372 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5373 PetscAssertPointer(depth, 3); 5374 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5375 PetscFunctionReturn(PETSC_SUCCESS); 5376 } 5377 5378 /*@ 5379 DMPlexGetPointHeight - Get the `height` of a given point 5380 5381 Not Collective 5382 5383 Input Parameters: 5384 + dm - The `DMPLEX` object 5385 - point - The point 5386 5387 Output Parameter: 5388 . height - The height of the `point` 5389 5390 Level: intermediate 5391 5392 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5393 @*/ 5394 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5395 { 5396 PetscInt n, pDepth; 5397 5398 PetscFunctionBegin; 5399 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5400 PetscAssertPointer(height, 3); 5401 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5402 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5403 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5404 PetscFunctionReturn(PETSC_SUCCESS); 5405 } 5406 5407 /*@ 5408 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5409 5410 Not Collective 5411 5412 Input Parameter: 5413 . dm - The `DMPLEX` object 5414 5415 Output Parameter: 5416 . celltypeLabel - The `DMLabel` recording cell polytope type 5417 5418 Level: developer 5419 5420 Note: 5421 This function will trigger automatica computation of cell types. This can be disabled by calling 5422 `DMCreateLabel`(dm, "celltype") beforehand. 5423 5424 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5425 @*/ 5426 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5427 { 5428 PetscFunctionBegin; 5429 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5430 PetscAssertPointer(celltypeLabel, 2); 5431 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5432 *celltypeLabel = dm->celltypeLabel; 5433 PetscFunctionReturn(PETSC_SUCCESS); 5434 } 5435 5436 /*@ 5437 DMPlexGetCellType - Get the polytope type of a given cell 5438 5439 Not Collective 5440 5441 Input Parameters: 5442 + dm - The `DMPLEX` object 5443 - cell - The cell 5444 5445 Output Parameter: 5446 . celltype - The polytope type of the cell 5447 5448 Level: intermediate 5449 5450 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5451 @*/ 5452 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5453 { 5454 DM_Plex *mesh = (DM_Plex *)dm->data; 5455 DMLabel label; 5456 PetscInt ct; 5457 5458 PetscFunctionBegin; 5459 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5460 PetscAssertPointer(celltype, 3); 5461 if (mesh->tr) { 5462 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5463 } else { 5464 PetscInt pStart, pEnd; 5465 5466 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5467 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5468 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5469 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5470 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5471 for (PetscInt p = pStart; p < pEnd; p++) { 5472 PetscCall(DMLabelGetValue(label, p, &ct)); 5473 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5474 } 5475 } 5476 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5477 if (PetscDefined(USE_DEBUG)) { 5478 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5479 PetscCall(DMLabelGetValue(label, cell, &ct)); 5480 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5481 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5482 } 5483 } 5484 PetscFunctionReturn(PETSC_SUCCESS); 5485 } 5486 5487 /*@ 5488 DMPlexSetCellType - Set the polytope type of a given cell 5489 5490 Not Collective 5491 5492 Input Parameters: 5493 + dm - The `DMPLEX` object 5494 . cell - The cell 5495 - celltype - The polytope type of the cell 5496 5497 Level: advanced 5498 5499 Note: 5500 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5501 is executed. This function will override the computed type. However, if automatic classification will not succeed 5502 and a user wants to manually specify all types, the classification must be disabled by calling 5503 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5504 5505 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5506 @*/ 5507 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5508 { 5509 DM_Plex *mesh = (DM_Plex *)dm->data; 5510 DMLabel label; 5511 PetscInt pStart, pEnd; 5512 5513 PetscFunctionBegin; 5514 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5515 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5516 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5517 PetscCall(DMLabelSetValue(label, cell, celltype)); 5518 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5519 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5520 PetscFunctionReturn(PETSC_SUCCESS); 5521 } 5522 5523 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5524 { 5525 PetscSection section, s; 5526 Mat m; 5527 PetscInt maxHeight; 5528 const char *prefix; 5529 5530 PetscFunctionBegin; 5531 PetscCall(DMClone(dm, cdm)); 5532 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5533 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5534 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5535 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5536 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5537 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5538 PetscCall(DMSetLocalSection(*cdm, section)); 5539 PetscCall(PetscSectionDestroy(§ion)); 5540 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5541 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5542 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5543 PetscCall(PetscSectionDestroy(&s)); 5544 PetscCall(MatDestroy(&m)); 5545 5546 PetscCall(DMSetNumFields(*cdm, 1)); 5547 PetscCall(DMCreateDS(*cdm)); 5548 (*cdm)->cloneOpts = PETSC_TRUE; 5549 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5550 PetscFunctionReturn(PETSC_SUCCESS); 5551 } 5552 5553 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5554 { 5555 Vec coordsLocal, cellCoordsLocal; 5556 DM coordsDM, cellCoordsDM; 5557 5558 PetscFunctionBegin; 5559 *field = NULL; 5560 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5561 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5562 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5563 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5564 if (coordsLocal && coordsDM) { 5565 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5566 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5567 } 5568 PetscFunctionReturn(PETSC_SUCCESS); 5569 } 5570 5571 /*@C 5572 DMPlexGetConeSection - Return a section which describes the layout of cone data 5573 5574 Not Collective 5575 5576 Input Parameter: 5577 . dm - The `DMPLEX` object 5578 5579 Output Parameter: 5580 . section - The `PetscSection` object 5581 5582 Level: developer 5583 5584 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5585 @*/ 5586 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5587 { 5588 DM_Plex *mesh = (DM_Plex *)dm->data; 5589 5590 PetscFunctionBegin; 5591 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5592 if (section) *section = mesh->coneSection; 5593 PetscFunctionReturn(PETSC_SUCCESS); 5594 } 5595 5596 /*@C 5597 DMPlexGetSupportSection - Return a section which describes the layout of support data 5598 5599 Not Collective 5600 5601 Input Parameter: 5602 . dm - The `DMPLEX` object 5603 5604 Output Parameter: 5605 . section - The `PetscSection` object 5606 5607 Level: developer 5608 5609 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5610 @*/ 5611 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5612 { 5613 DM_Plex *mesh = (DM_Plex *)dm->data; 5614 5615 PetscFunctionBegin; 5616 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5617 if (section) *section = mesh->supportSection; 5618 PetscFunctionReturn(PETSC_SUCCESS); 5619 } 5620 5621 /*@C 5622 DMPlexGetCones - Return cone data 5623 5624 Not Collective 5625 5626 Input Parameter: 5627 . dm - The `DMPLEX` object 5628 5629 Output Parameter: 5630 . cones - The cone for each point 5631 5632 Level: developer 5633 5634 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5635 @*/ 5636 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5637 { 5638 DM_Plex *mesh = (DM_Plex *)dm->data; 5639 5640 PetscFunctionBegin; 5641 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5642 if (cones) *cones = mesh->cones; 5643 PetscFunctionReturn(PETSC_SUCCESS); 5644 } 5645 5646 /*@C 5647 DMPlexGetConeOrientations - Return cone orientation data 5648 5649 Not Collective 5650 5651 Input Parameter: 5652 . dm - The `DMPLEX` object 5653 5654 Output Parameter: 5655 . coneOrientations - The array of cone orientations for all points 5656 5657 Level: developer 5658 5659 Notes: 5660 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5661 5662 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5663 5664 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5665 @*/ 5666 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5667 { 5668 DM_Plex *mesh = (DM_Plex *)dm->data; 5669 5670 PetscFunctionBegin; 5671 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5672 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5673 PetscFunctionReturn(PETSC_SUCCESS); 5674 } 5675 5676 /******************************** FEM Support **********************************/ 5677 5678 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5679 { 5680 PetscInt depth; 5681 5682 PetscFunctionBegin; 5683 PetscCall(DMPlexGetDepth(plex, &depth)); 5684 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5685 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5686 PetscFunctionReturn(PETSC_SUCCESS); 5687 } 5688 5689 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5690 { 5691 PetscInt depth; 5692 5693 PetscFunctionBegin; 5694 PetscCall(DMPlexGetDepth(plex, &depth)); 5695 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5696 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5697 PetscFunctionReturn(PETSC_SUCCESS); 5698 } 5699 5700 /* 5701 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5702 representing a line in the section. 5703 */ 5704 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5705 { 5706 PetscObject obj; 5707 PetscClassId id; 5708 PetscFE fe = NULL; 5709 5710 PetscFunctionBeginHot; 5711 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5712 PetscCall(DMGetField(dm, field, NULL, &obj)); 5713 PetscCall(PetscObjectGetClassId(obj, &id)); 5714 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5715 5716 if (!fe) { 5717 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5718 /* An order k SEM disc has k-1 dofs on an edge */ 5719 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5720 *k = *k / *Nc + 1; 5721 } else { 5722 PetscInt dual_space_size, dim; 5723 PetscDualSpace dsp; 5724 5725 PetscCall(DMGetDimension(dm, &dim)); 5726 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5727 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5728 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5729 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5730 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5731 } 5732 PetscFunctionReturn(PETSC_SUCCESS); 5733 } 5734 5735 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5736 { 5737 PetscFunctionBeginHot; 5738 if (tensor) { 5739 *dof = PetscPowInt(k + 1, dim); 5740 } else { 5741 switch (dim) { 5742 case 1: 5743 *dof = k + 1; 5744 break; 5745 case 2: 5746 *dof = ((k + 1) * (k + 2)) / 2; 5747 break; 5748 case 3: 5749 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5750 break; 5751 default: 5752 *dof = 0; 5753 } 5754 } 5755 PetscFunctionReturn(PETSC_SUCCESS); 5756 } 5757 5758 /*@ 5759 5760 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5761 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5762 section provided (or the section of the `DM`). 5763 5764 Input Parameters: 5765 + dm - The `DM` 5766 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5767 - section - The `PetscSection` to reorder, or `NULL` for the default section 5768 5769 Example: 5770 A typical interpolated single-quad mesh might order points as 5771 .vb 5772 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5773 5774 v4 -- e6 -- v3 5775 | | 5776 e7 c0 e8 5777 | | 5778 v1 -- e5 -- v2 5779 .ve 5780 5781 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5782 dofs in the order of points, e.g., 5783 .vb 5784 c0 -> [0,1,2,3] 5785 v1 -> [4] 5786 ... 5787 e5 -> [8, 9] 5788 .ve 5789 5790 which corresponds to the dofs 5791 .vb 5792 6 10 11 7 5793 13 2 3 15 5794 12 0 1 14 5795 4 8 9 5 5796 .ve 5797 5798 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5799 .vb 5800 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5801 .ve 5802 5803 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5804 .vb 5805 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5806 .ve 5807 5808 Level: developer 5809 5810 Notes: 5811 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5812 degree of the basis. 5813 5814 This is required to run with libCEED. 5815 5816 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5817 @*/ 5818 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5819 { 5820 DMLabel label; 5821 PetscInt dim, depth = -1, eStart = -1, Nf; 5822 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5823 5824 PetscFunctionBegin; 5825 PetscCall(DMGetDimension(dm, &dim)); 5826 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5827 if (point < 0) { 5828 PetscInt sStart, sEnd; 5829 5830 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5831 point = sEnd - sStart ? sStart : point; 5832 } 5833 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5834 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5835 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5836 if (depth == 1) { 5837 eStart = point; 5838 } else if (depth == dim) { 5839 const PetscInt *cone; 5840 5841 PetscCall(DMPlexGetCone(dm, point, &cone)); 5842 if (dim == 2) eStart = cone[0]; 5843 else if (dim == 3) { 5844 const PetscInt *cone2; 5845 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5846 eStart = cone2[0]; 5847 } 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); 5848 } 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); 5849 5850 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5851 for (PetscInt d = 1; d <= dim; d++) { 5852 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5853 PetscInt *perm; 5854 5855 for (f = 0; f < Nf; ++f) { 5856 PetscInt dof; 5857 5858 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5859 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5860 if (!continuous && d < dim) continue; 5861 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5862 size += dof * Nc; 5863 } 5864 PetscCall(PetscMalloc1(size, &perm)); 5865 for (f = 0; f < Nf; ++f) { 5866 switch (d) { 5867 case 1: 5868 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5869 if (!continuous && d < dim) continue; 5870 /* 5871 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5872 We want [ vtx0; edge of length k-1; vtx1 ] 5873 */ 5874 if (continuous) { 5875 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5876 for (i = 0; i < k - 1; i++) 5877 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5878 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5879 foffset = offset; 5880 } else { 5881 PetscInt dof; 5882 5883 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5884 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5885 foffset = offset; 5886 } 5887 break; 5888 case 2: 5889 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5890 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5891 if (!continuous && d < dim) continue; 5892 /* The SEM order is 5893 5894 v_lb, {e_b}, v_rb, 5895 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5896 v_lt, reverse {e_t}, v_rt 5897 */ 5898 if (continuous) { 5899 const PetscInt of = 0; 5900 const PetscInt oeb = of + PetscSqr(k - 1); 5901 const PetscInt oer = oeb + (k - 1); 5902 const PetscInt oet = oer + (k - 1); 5903 const PetscInt oel = oet + (k - 1); 5904 const PetscInt ovlb = oel + (k - 1); 5905 const PetscInt ovrb = ovlb + 1; 5906 const PetscInt ovrt = ovrb + 1; 5907 const PetscInt ovlt = ovrt + 1; 5908 PetscInt o; 5909 5910 /* bottom */ 5911 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5912 for (o = oeb; o < oer; ++o) 5913 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5914 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5915 /* middle */ 5916 for (i = 0; i < k - 1; ++i) { 5917 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5918 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5919 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5920 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5921 } 5922 /* top */ 5923 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5924 for (o = oel - 1; o >= oet; --o) 5925 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5926 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5927 foffset = offset; 5928 } else { 5929 PetscInt dof; 5930 5931 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5932 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5933 foffset = offset; 5934 } 5935 break; 5936 case 3: 5937 /* The original hex closure is 5938 5939 {c, 5940 f_b, f_t, f_f, f_b, f_r, f_l, 5941 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5942 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5943 */ 5944 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5945 if (!continuous && d < dim) continue; 5946 /* The SEM order is 5947 Bottom Slice 5948 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5949 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5950 v_blb, {e_bb}, v_brb, 5951 5952 Middle Slice (j) 5953 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5954 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5955 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5956 5957 Top Slice 5958 v_tlf, {e_tf}, v_trf, 5959 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5960 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5961 */ 5962 if (continuous) { 5963 const PetscInt oc = 0; 5964 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5965 const PetscInt oft = ofb + PetscSqr(k - 1); 5966 const PetscInt off = oft + PetscSqr(k - 1); 5967 const PetscInt ofk = off + PetscSqr(k - 1); 5968 const PetscInt ofr = ofk + PetscSqr(k - 1); 5969 const PetscInt ofl = ofr + PetscSqr(k - 1); 5970 const PetscInt oebl = ofl + PetscSqr(k - 1); 5971 const PetscInt oebb = oebl + (k - 1); 5972 const PetscInt oebr = oebb + (k - 1); 5973 const PetscInt oebf = oebr + (k - 1); 5974 const PetscInt oetf = oebf + (k - 1); 5975 const PetscInt oetr = oetf + (k - 1); 5976 const PetscInt oetb = oetr + (k - 1); 5977 const PetscInt oetl = oetb + (k - 1); 5978 const PetscInt oerf = oetl + (k - 1); 5979 const PetscInt oelf = oerf + (k - 1); 5980 const PetscInt oelb = oelf + (k - 1); 5981 const PetscInt oerb = oelb + (k - 1); 5982 const PetscInt ovblf = oerb + (k - 1); 5983 const PetscInt ovblb = ovblf + 1; 5984 const PetscInt ovbrb = ovblb + 1; 5985 const PetscInt ovbrf = ovbrb + 1; 5986 const PetscInt ovtlf = ovbrf + 1; 5987 const PetscInt ovtrf = ovtlf + 1; 5988 const PetscInt ovtrb = ovtrf + 1; 5989 const PetscInt ovtlb = ovtrb + 1; 5990 PetscInt o, n; 5991 5992 /* Bottom Slice */ 5993 /* bottom */ 5994 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5995 for (o = oetf - 1; o >= oebf; --o) 5996 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5997 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5998 /* middle */ 5999 for (i = 0; i < k - 1; ++i) { 6000 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6001 for (n = 0; n < k - 1; ++n) { 6002 o = ofb + n * (k - 1) + i; 6003 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6004 } 6005 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6006 } 6007 /* top */ 6008 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6009 for (o = oebb; o < oebr; ++o) 6010 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6011 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6012 6013 /* Middle Slice */ 6014 for (j = 0; j < k - 1; ++j) { 6015 /* bottom */ 6016 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6017 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6018 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6019 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6020 /* middle */ 6021 for (i = 0; i < k - 1; ++i) { 6022 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6023 for (n = 0; n < k - 1; ++n) 6024 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6025 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6026 } 6027 /* top */ 6028 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6029 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6030 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6031 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6032 } 6033 6034 /* Top Slice */ 6035 /* bottom */ 6036 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6037 for (o = oetf; o < oetr; ++o) 6038 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6039 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6040 /* middle */ 6041 for (i = 0; i < k - 1; ++i) { 6042 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6043 for (n = 0; n < k - 1; ++n) 6044 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6045 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6046 } 6047 /* top */ 6048 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6049 for (o = oetl - 1; o >= oetb; --o) 6050 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6051 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6052 6053 foffset = offset; 6054 } else { 6055 PetscInt dof; 6056 6057 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6058 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6059 foffset = offset; 6060 } 6061 break; 6062 default: 6063 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6064 } 6065 } 6066 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6067 /* Check permutation */ 6068 { 6069 PetscInt *check; 6070 6071 PetscCall(PetscMalloc1(size, &check)); 6072 for (i = 0; i < size; ++i) { 6073 check[i] = -1; 6074 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6075 } 6076 for (i = 0; i < size; ++i) check[perm[i]] = i; 6077 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6078 PetscCall(PetscFree(check)); 6079 } 6080 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6081 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6082 PetscInt *loc_perm; 6083 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6084 for (PetscInt i = 0; i < size; i++) { 6085 loc_perm[i] = perm[i]; 6086 loc_perm[size + i] = size + perm[i]; 6087 } 6088 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6089 } 6090 } 6091 PetscFunctionReturn(PETSC_SUCCESS); 6092 } 6093 6094 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6095 { 6096 PetscDS prob; 6097 PetscInt depth, Nf, h; 6098 DMLabel label; 6099 6100 PetscFunctionBeginHot; 6101 PetscCall(DMGetDS(dm, &prob)); 6102 Nf = prob->Nf; 6103 label = dm->depthLabel; 6104 *dspace = NULL; 6105 if (field < Nf) { 6106 PetscObject disc = prob->disc[field]; 6107 6108 if (disc->classid == PETSCFE_CLASSID) { 6109 PetscDualSpace dsp; 6110 6111 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6112 PetscCall(DMLabelGetNumValues(label, &depth)); 6113 PetscCall(DMLabelGetValue(label, point, &h)); 6114 h = depth - 1 - h; 6115 if (h) { 6116 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6117 } else { 6118 *dspace = dsp; 6119 } 6120 } 6121 } 6122 PetscFunctionReturn(PETSC_SUCCESS); 6123 } 6124 6125 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6126 { 6127 PetscScalar *array; 6128 const PetscScalar *vArray; 6129 const PetscInt *cone, *coneO; 6130 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6131 6132 PetscFunctionBeginHot; 6133 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6134 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6135 PetscCall(DMPlexGetCone(dm, point, &cone)); 6136 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6137 if (!values || !*values) { 6138 if ((point >= pStart) && (point < pEnd)) { 6139 PetscInt dof; 6140 6141 PetscCall(PetscSectionGetDof(section, point, &dof)); 6142 size += dof; 6143 } 6144 for (p = 0; p < numPoints; ++p) { 6145 const PetscInt cp = cone[p]; 6146 PetscInt dof; 6147 6148 if ((cp < pStart) || (cp >= pEnd)) continue; 6149 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6150 size += dof; 6151 } 6152 if (!values) { 6153 if (csize) *csize = size; 6154 PetscFunctionReturn(PETSC_SUCCESS); 6155 } 6156 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6157 } else { 6158 array = *values; 6159 } 6160 size = 0; 6161 PetscCall(VecGetArrayRead(v, &vArray)); 6162 if ((point >= pStart) && (point < pEnd)) { 6163 PetscInt dof, off, d; 6164 const PetscScalar *varr; 6165 6166 PetscCall(PetscSectionGetDof(section, point, &dof)); 6167 PetscCall(PetscSectionGetOffset(section, point, &off)); 6168 varr = PetscSafePointerPlusOffset(vArray, off); 6169 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6170 size += dof; 6171 } 6172 for (p = 0; p < numPoints; ++p) { 6173 const PetscInt cp = cone[p]; 6174 PetscInt o = coneO[p]; 6175 PetscInt dof, off, d; 6176 const PetscScalar *varr; 6177 6178 if ((cp < pStart) || (cp >= pEnd)) continue; 6179 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6180 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6181 varr = PetscSafePointerPlusOffset(vArray, off); 6182 if (o >= 0) { 6183 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6184 } else { 6185 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6186 } 6187 size += dof; 6188 } 6189 PetscCall(VecRestoreArrayRead(v, &vArray)); 6190 if (!*values) { 6191 if (csize) *csize = size; 6192 *values = array; 6193 } else { 6194 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6195 *csize = size; 6196 } 6197 PetscFunctionReturn(PETSC_SUCCESS); 6198 } 6199 6200 /* Compress out points not in the section */ 6201 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6202 { 6203 const PetscInt np = *numPoints; 6204 PetscInt pStart, pEnd, p, q; 6205 6206 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6207 for (p = 0, q = 0; p < np; ++p) { 6208 const PetscInt r = points[p * 2]; 6209 if ((r >= pStart) && (r < pEnd)) { 6210 points[q * 2] = r; 6211 points[q * 2 + 1] = points[p * 2 + 1]; 6212 ++q; 6213 } 6214 } 6215 *numPoints = q; 6216 return PETSC_SUCCESS; 6217 } 6218 6219 /* Compressed closure does not apply closure permutation */ 6220 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6221 { 6222 const PetscInt *cla = NULL; 6223 PetscInt np, *pts = NULL; 6224 6225 PetscFunctionBeginHot; 6226 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6227 if (!ornt && *clPoints) { 6228 PetscInt dof, off; 6229 6230 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6231 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6232 PetscCall(ISGetIndices(*clPoints, &cla)); 6233 np = dof / 2; 6234 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6235 } else { 6236 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6237 PetscCall(CompressPoints_Private(section, &np, pts)); 6238 } 6239 *numPoints = np; 6240 *points = pts; 6241 *clp = cla; 6242 PetscFunctionReturn(PETSC_SUCCESS); 6243 } 6244 6245 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6246 { 6247 PetscFunctionBeginHot; 6248 if (!*clPoints) { 6249 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6250 } else { 6251 PetscCall(ISRestoreIndices(*clPoints, clp)); 6252 } 6253 *numPoints = 0; 6254 *points = NULL; 6255 *clSec = NULL; 6256 *clPoints = NULL; 6257 *clp = NULL; 6258 PetscFunctionReturn(PETSC_SUCCESS); 6259 } 6260 6261 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6262 { 6263 PetscInt offset = 0, p; 6264 const PetscInt **perms = NULL; 6265 const PetscScalar **flips = NULL; 6266 6267 PetscFunctionBeginHot; 6268 *size = 0; 6269 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6270 for (p = 0; p < numPoints; p++) { 6271 const PetscInt point = points[2 * p]; 6272 const PetscInt *perm = perms ? perms[p] : NULL; 6273 const PetscScalar *flip = flips ? flips[p] : NULL; 6274 PetscInt dof, off, d; 6275 const PetscScalar *varr; 6276 6277 PetscCall(PetscSectionGetDof(section, point, &dof)); 6278 PetscCall(PetscSectionGetOffset(section, point, &off)); 6279 varr = PetscSafePointerPlusOffset(vArray, off); 6280 if (clperm) { 6281 if (perm) { 6282 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6283 } else { 6284 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6285 } 6286 if (flip) { 6287 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6288 } 6289 } else { 6290 if (perm) { 6291 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6292 } else { 6293 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6294 } 6295 if (flip) { 6296 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6297 } 6298 } 6299 offset += dof; 6300 } 6301 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6302 *size = offset; 6303 PetscFunctionReturn(PETSC_SUCCESS); 6304 } 6305 6306 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[]) 6307 { 6308 PetscInt offset = 0, f; 6309 6310 PetscFunctionBeginHot; 6311 *size = 0; 6312 for (f = 0; f < numFields; ++f) { 6313 PetscInt p; 6314 const PetscInt **perms = NULL; 6315 const PetscScalar **flips = NULL; 6316 6317 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6318 for (p = 0; p < numPoints; p++) { 6319 const PetscInt point = points[2 * p]; 6320 PetscInt fdof, foff, b; 6321 const PetscScalar *varr; 6322 const PetscInt *perm = perms ? perms[p] : NULL; 6323 const PetscScalar *flip = flips ? flips[p] : NULL; 6324 6325 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6326 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6327 varr = &vArray[foff]; 6328 if (clperm) { 6329 if (perm) { 6330 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6331 } else { 6332 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6333 } 6334 if (flip) { 6335 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6336 } 6337 } else { 6338 if (perm) { 6339 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6340 } else { 6341 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6342 } 6343 if (flip) { 6344 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6345 } 6346 } 6347 offset += fdof; 6348 } 6349 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6350 } 6351 *size = offset; 6352 PetscFunctionReturn(PETSC_SUCCESS); 6353 } 6354 6355 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6356 { 6357 PetscSection clSection; 6358 IS clPoints; 6359 PetscInt *points = NULL; 6360 const PetscInt *clp, *perm = NULL; 6361 PetscInt depth, numFields, numPoints, asize; 6362 6363 PetscFunctionBeginHot; 6364 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6365 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6366 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6367 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6368 PetscCall(DMPlexGetDepth(dm, &depth)); 6369 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6370 if (depth == 1 && numFields < 2) { 6371 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6372 PetscFunctionReturn(PETSC_SUCCESS); 6373 } 6374 /* Get points */ 6375 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6376 /* Get sizes */ 6377 asize = 0; 6378 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6379 PetscInt dof; 6380 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6381 asize += dof; 6382 } 6383 if (values) { 6384 const PetscScalar *vArray; 6385 PetscInt size; 6386 6387 if (*values) { 6388 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); 6389 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6390 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6391 PetscCall(VecGetArrayRead(v, &vArray)); 6392 /* Get values */ 6393 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6394 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6395 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6396 /* Cleanup array */ 6397 PetscCall(VecRestoreArrayRead(v, &vArray)); 6398 } 6399 if (csize) *csize = asize; 6400 /* Cleanup points */ 6401 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6402 PetscFunctionReturn(PETSC_SUCCESS); 6403 } 6404 6405 /*@C 6406 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6407 6408 Not collective 6409 6410 Input Parameters: 6411 + dm - The `DM` 6412 . section - The section describing the layout in `v`, or `NULL` to use the default section 6413 . v - The local vector 6414 - point - The point in the `DM` 6415 6416 Input/Output Parameters: 6417 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6418 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6419 if the user provided `NULL`, it is a borrowed array and should not be freed 6420 6421 Level: intermediate 6422 6423 Notes: 6424 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6425 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6426 assembly function, and a user may already have allocated storage for this operation. 6427 6428 A typical use could be 6429 .vb 6430 values = NULL; 6431 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6432 for (cl = 0; cl < clSize; ++cl) { 6433 <Compute on closure> 6434 } 6435 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6436 .ve 6437 or 6438 .vb 6439 PetscMalloc1(clMaxSize, &values); 6440 for (p = pStart; p < pEnd; ++p) { 6441 clSize = clMaxSize; 6442 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6443 for (cl = 0; cl < clSize; ++cl) { 6444 <Compute on closure> 6445 } 6446 } 6447 PetscFree(values); 6448 .ve 6449 6450 Fortran Notes: 6451 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6452 6453 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6454 @*/ 6455 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6456 { 6457 PetscFunctionBeginHot; 6458 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6459 PetscFunctionReturn(PETSC_SUCCESS); 6460 } 6461 6462 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6463 { 6464 DMLabel depthLabel; 6465 PetscSection clSection; 6466 IS clPoints; 6467 PetscScalar *array; 6468 const PetscScalar *vArray; 6469 PetscInt *points = NULL; 6470 const PetscInt *clp, *perm = NULL; 6471 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6472 6473 PetscFunctionBeginHot; 6474 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6475 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6476 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6477 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6478 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6479 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6480 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6481 if (mdepth == 1 && numFields < 2) { 6482 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6483 PetscFunctionReturn(PETSC_SUCCESS); 6484 } 6485 /* Get points */ 6486 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6487 for (clsize = 0, p = 0; p < Np; p++) { 6488 PetscInt dof; 6489 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6490 clsize += dof; 6491 } 6492 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6493 /* Filter points */ 6494 for (p = 0; p < numPoints * 2; p += 2) { 6495 PetscInt dep; 6496 6497 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6498 if (dep != depth) continue; 6499 points[Np * 2 + 0] = points[p]; 6500 points[Np * 2 + 1] = points[p + 1]; 6501 ++Np; 6502 } 6503 /* Get array */ 6504 if (!values || !*values) { 6505 PetscInt asize = 0, dof; 6506 6507 for (p = 0; p < Np * 2; p += 2) { 6508 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6509 asize += dof; 6510 } 6511 if (!values) { 6512 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6513 if (csize) *csize = asize; 6514 PetscFunctionReturn(PETSC_SUCCESS); 6515 } 6516 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6517 } else { 6518 array = *values; 6519 } 6520 PetscCall(VecGetArrayRead(v, &vArray)); 6521 /* Get values */ 6522 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6523 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6524 /* Cleanup points */ 6525 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6526 /* Cleanup array */ 6527 PetscCall(VecRestoreArrayRead(v, &vArray)); 6528 if (!*values) { 6529 if (csize) *csize = size; 6530 *values = array; 6531 } else { 6532 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6533 *csize = size; 6534 } 6535 PetscFunctionReturn(PETSC_SUCCESS); 6536 } 6537 6538 /*@C 6539 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6540 6541 Not collective 6542 6543 Input Parameters: 6544 + dm - The `DM` 6545 . section - The section describing the layout in `v`, or `NULL` to use the default section 6546 . v - The local vector 6547 . point - The point in the `DM` 6548 . csize - The number of values in the closure, or `NULL` 6549 - values - The array of values, which is a borrowed array and should not be freed 6550 6551 Level: intermediate 6552 6553 Note: 6554 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6555 6556 Fortran Notes: 6557 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6558 6559 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6560 @*/ 6561 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6562 { 6563 PetscInt size = 0; 6564 6565 PetscFunctionBegin; 6566 /* Should work without recalculating size */ 6567 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6568 *values = NULL; 6569 PetscFunctionReturn(PETSC_SUCCESS); 6570 } 6571 6572 static inline void add(PetscScalar *x, PetscScalar y) 6573 { 6574 *x += y; 6575 } 6576 static inline void insert(PetscScalar *x, PetscScalar y) 6577 { 6578 *x = y; 6579 } 6580 6581 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[]) 6582 { 6583 PetscInt cdof; /* The number of constraints on this point */ 6584 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6585 PetscScalar *a; 6586 PetscInt off, cind = 0, k; 6587 6588 PetscFunctionBegin; 6589 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6590 PetscCall(PetscSectionGetOffset(section, point, &off)); 6591 a = &array[off]; 6592 if (!cdof || setBC) { 6593 if (clperm) { 6594 if (perm) { 6595 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6596 } else { 6597 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6598 } 6599 } else { 6600 if (perm) { 6601 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6602 } else { 6603 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6604 } 6605 } 6606 } else { 6607 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6608 if (clperm) { 6609 if (perm) { 6610 for (k = 0; k < dof; ++k) { 6611 if ((cind < cdof) && (k == cdofs[cind])) { 6612 ++cind; 6613 continue; 6614 } 6615 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6616 } 6617 } else { 6618 for (k = 0; k < dof; ++k) { 6619 if ((cind < cdof) && (k == cdofs[cind])) { 6620 ++cind; 6621 continue; 6622 } 6623 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6624 } 6625 } 6626 } else { 6627 if (perm) { 6628 for (k = 0; k < dof; ++k) { 6629 if ((cind < cdof) && (k == cdofs[cind])) { 6630 ++cind; 6631 continue; 6632 } 6633 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6634 } 6635 } else { 6636 for (k = 0; k < dof; ++k) { 6637 if ((cind < cdof) && (k == cdofs[cind])) { 6638 ++cind; 6639 continue; 6640 } 6641 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6642 } 6643 } 6644 } 6645 } 6646 PetscFunctionReturn(PETSC_SUCCESS); 6647 } 6648 6649 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[]) 6650 { 6651 PetscInt cdof; /* The number of constraints on this point */ 6652 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6653 PetscScalar *a; 6654 PetscInt off, cind = 0, k; 6655 6656 PetscFunctionBegin; 6657 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6658 PetscCall(PetscSectionGetOffset(section, point, &off)); 6659 a = &array[off]; 6660 if (cdof) { 6661 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6662 if (clperm) { 6663 if (perm) { 6664 for (k = 0; k < dof; ++k) { 6665 if ((cind < cdof) && (k == cdofs[cind])) { 6666 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6667 cind++; 6668 } 6669 } 6670 } else { 6671 for (k = 0; k < dof; ++k) { 6672 if ((cind < cdof) && (k == cdofs[cind])) { 6673 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6674 cind++; 6675 } 6676 } 6677 } 6678 } else { 6679 if (perm) { 6680 for (k = 0; k < dof; ++k) { 6681 if ((cind < cdof) && (k == cdofs[cind])) { 6682 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6683 cind++; 6684 } 6685 } 6686 } else { 6687 for (k = 0; k < dof; ++k) { 6688 if ((cind < cdof) && (k == cdofs[cind])) { 6689 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6690 cind++; 6691 } 6692 } 6693 } 6694 } 6695 } 6696 PetscFunctionReturn(PETSC_SUCCESS); 6697 } 6698 6699 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[]) 6700 { 6701 PetscScalar *a; 6702 PetscInt fdof, foff, fcdof, foffset = *offset; 6703 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6704 PetscInt cind = 0, b; 6705 6706 PetscFunctionBegin; 6707 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6708 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6709 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6710 a = &array[foff]; 6711 if (!fcdof || setBC) { 6712 if (clperm) { 6713 if (perm) { 6714 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6715 } else { 6716 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6717 } 6718 } else { 6719 if (perm) { 6720 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6721 } else { 6722 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6723 } 6724 } 6725 } else { 6726 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6727 if (clperm) { 6728 if (perm) { 6729 for (b = 0; b < fdof; b++) { 6730 if ((cind < fcdof) && (b == fcdofs[cind])) { 6731 ++cind; 6732 continue; 6733 } 6734 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6735 } 6736 } else { 6737 for (b = 0; b < fdof; b++) { 6738 if ((cind < fcdof) && (b == fcdofs[cind])) { 6739 ++cind; 6740 continue; 6741 } 6742 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6743 } 6744 } 6745 } else { 6746 if (perm) { 6747 for (b = 0; b < fdof; b++) { 6748 if ((cind < fcdof) && (b == fcdofs[cind])) { 6749 ++cind; 6750 continue; 6751 } 6752 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6753 } 6754 } else { 6755 for (b = 0; b < fdof; b++) { 6756 if ((cind < fcdof) && (b == fcdofs[cind])) { 6757 ++cind; 6758 continue; 6759 } 6760 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6761 } 6762 } 6763 } 6764 } 6765 *offset += fdof; 6766 PetscFunctionReturn(PETSC_SUCCESS); 6767 } 6768 6769 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[]) 6770 { 6771 PetscScalar *a; 6772 PetscInt fdof, foff, fcdof, foffset = *offset; 6773 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6774 PetscInt Nc, cind = 0, ncind = 0, b; 6775 PetscBool ncSet, fcSet; 6776 6777 PetscFunctionBegin; 6778 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6779 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6780 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6781 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6782 a = &array[foff]; 6783 if (fcdof) { 6784 /* We just override fcdof and fcdofs with Ncc and comps */ 6785 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6786 if (clperm) { 6787 if (perm) { 6788 if (comps) { 6789 for (b = 0; b < fdof; b++) { 6790 ncSet = fcSet = PETSC_FALSE; 6791 if (b % Nc == comps[ncind]) { 6792 ncind = (ncind + 1) % Ncc; 6793 ncSet = PETSC_TRUE; 6794 } 6795 if ((cind < fcdof) && (b == fcdofs[cind])) { 6796 ++cind; 6797 fcSet = PETSC_TRUE; 6798 } 6799 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6800 } 6801 } else { 6802 for (b = 0; b < fdof; b++) { 6803 if ((cind < fcdof) && (b == fcdofs[cind])) { 6804 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6805 ++cind; 6806 } 6807 } 6808 } 6809 } else { 6810 if (comps) { 6811 for (b = 0; b < fdof; b++) { 6812 ncSet = fcSet = PETSC_FALSE; 6813 if (b % Nc == comps[ncind]) { 6814 ncind = (ncind + 1) % Ncc; 6815 ncSet = PETSC_TRUE; 6816 } 6817 if ((cind < fcdof) && (b == fcdofs[cind])) { 6818 ++cind; 6819 fcSet = PETSC_TRUE; 6820 } 6821 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6822 } 6823 } else { 6824 for (b = 0; b < fdof; b++) { 6825 if ((cind < fcdof) && (b == fcdofs[cind])) { 6826 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6827 ++cind; 6828 } 6829 } 6830 } 6831 } 6832 } else { 6833 if (perm) { 6834 if (comps) { 6835 for (b = 0; b < fdof; b++) { 6836 ncSet = fcSet = PETSC_FALSE; 6837 if (b % Nc == comps[ncind]) { 6838 ncind = (ncind + 1) % Ncc; 6839 ncSet = PETSC_TRUE; 6840 } 6841 if ((cind < fcdof) && (b == fcdofs[cind])) { 6842 ++cind; 6843 fcSet = PETSC_TRUE; 6844 } 6845 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6846 } 6847 } else { 6848 for (b = 0; b < fdof; b++) { 6849 if ((cind < fcdof) && (b == fcdofs[cind])) { 6850 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6851 ++cind; 6852 } 6853 } 6854 } 6855 } else { 6856 if (comps) { 6857 for (b = 0; b < fdof; b++) { 6858 ncSet = fcSet = PETSC_FALSE; 6859 if (b % Nc == comps[ncind]) { 6860 ncind = (ncind + 1) % Ncc; 6861 ncSet = PETSC_TRUE; 6862 } 6863 if ((cind < fcdof) && (b == fcdofs[cind])) { 6864 ++cind; 6865 fcSet = PETSC_TRUE; 6866 } 6867 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6868 } 6869 } else { 6870 for (b = 0; b < fdof; b++) { 6871 if ((cind < fcdof) && (b == fcdofs[cind])) { 6872 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6873 ++cind; 6874 } 6875 } 6876 } 6877 } 6878 } 6879 } 6880 *offset += fdof; 6881 PetscFunctionReturn(PETSC_SUCCESS); 6882 } 6883 6884 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6885 { 6886 PetscScalar *array; 6887 const PetscInt *cone, *coneO; 6888 PetscInt pStart, pEnd, p, numPoints, off, dof; 6889 6890 PetscFunctionBeginHot; 6891 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6892 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6893 PetscCall(DMPlexGetCone(dm, point, &cone)); 6894 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6895 PetscCall(VecGetArray(v, &array)); 6896 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6897 const PetscInt cp = !p ? point : cone[p - 1]; 6898 const PetscInt o = !p ? 0 : coneO[p - 1]; 6899 6900 if ((cp < pStart) || (cp >= pEnd)) { 6901 dof = 0; 6902 continue; 6903 } 6904 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6905 /* ADD_VALUES */ 6906 { 6907 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6908 PetscScalar *a; 6909 PetscInt cdof, coff, cind = 0, k; 6910 6911 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6912 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6913 a = &array[coff]; 6914 if (!cdof) { 6915 if (o >= 0) { 6916 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6917 } else { 6918 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6919 } 6920 } else { 6921 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6922 if (o >= 0) { 6923 for (k = 0; k < dof; ++k) { 6924 if ((cind < cdof) && (k == cdofs[cind])) { 6925 ++cind; 6926 continue; 6927 } 6928 a[k] += values[off + k]; 6929 } 6930 } else { 6931 for (k = 0; k < dof; ++k) { 6932 if ((cind < cdof) && (k == cdofs[cind])) { 6933 ++cind; 6934 continue; 6935 } 6936 a[k] += values[off + dof - k - 1]; 6937 } 6938 } 6939 } 6940 } 6941 } 6942 PetscCall(VecRestoreArray(v, &array)); 6943 PetscFunctionReturn(PETSC_SUCCESS); 6944 } 6945 6946 /*@C 6947 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6948 6949 Not collective 6950 6951 Input Parameters: 6952 + dm - The `DM` 6953 . section - The section describing the layout in `v`, or `NULL` to use the default section 6954 . v - The local vector 6955 . point - The point in the `DM` 6956 . values - The array of values 6957 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6958 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6959 6960 Level: intermediate 6961 6962 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6963 @*/ 6964 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6965 { 6966 PetscSection clSection; 6967 IS clPoints; 6968 PetscScalar *array; 6969 PetscInt *points = NULL; 6970 const PetscInt *clp, *clperm = NULL; 6971 PetscInt depth, numFields, numPoints, p, clsize; 6972 6973 PetscFunctionBeginHot; 6974 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6975 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6976 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6977 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6978 PetscCall(DMPlexGetDepth(dm, &depth)); 6979 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6980 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6981 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6982 PetscFunctionReturn(PETSC_SUCCESS); 6983 } 6984 /* Get points */ 6985 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6986 for (clsize = 0, p = 0; p < numPoints; p++) { 6987 PetscInt dof; 6988 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6989 clsize += dof; 6990 } 6991 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6992 /* Get array */ 6993 PetscCall(VecGetArray(v, &array)); 6994 /* Get values */ 6995 if (numFields > 0) { 6996 PetscInt offset = 0, f; 6997 for (f = 0; f < numFields; ++f) { 6998 const PetscInt **perms = NULL; 6999 const PetscScalar **flips = NULL; 7000 7001 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7002 switch (mode) { 7003 case INSERT_VALUES: 7004 for (p = 0; p < numPoints; p++) { 7005 const PetscInt point = points[2 * p]; 7006 const PetscInt *perm = perms ? perms[p] : NULL; 7007 const PetscScalar *flip = flips ? flips[p] : NULL; 7008 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7009 } 7010 break; 7011 case INSERT_ALL_VALUES: 7012 for (p = 0; p < numPoints; p++) { 7013 const PetscInt point = points[2 * p]; 7014 const PetscInt *perm = perms ? perms[p] : NULL; 7015 const PetscScalar *flip = flips ? flips[p] : NULL; 7016 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7017 } 7018 break; 7019 case INSERT_BC_VALUES: 7020 for (p = 0; p < numPoints; p++) { 7021 const PetscInt point = points[2 * p]; 7022 const PetscInt *perm = perms ? perms[p] : NULL; 7023 const PetscScalar *flip = flips ? flips[p] : NULL; 7024 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7025 } 7026 break; 7027 case ADD_VALUES: 7028 for (p = 0; p < numPoints; p++) { 7029 const PetscInt point = points[2 * p]; 7030 const PetscInt *perm = perms ? perms[p] : NULL; 7031 const PetscScalar *flip = flips ? flips[p] : NULL; 7032 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7033 } 7034 break; 7035 case ADD_ALL_VALUES: 7036 for (p = 0; p < numPoints; p++) { 7037 const PetscInt point = points[2 * p]; 7038 const PetscInt *perm = perms ? perms[p] : NULL; 7039 const PetscScalar *flip = flips ? flips[p] : NULL; 7040 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7041 } 7042 break; 7043 case ADD_BC_VALUES: 7044 for (p = 0; p < numPoints; p++) { 7045 const PetscInt point = points[2 * p]; 7046 const PetscInt *perm = perms ? perms[p] : NULL; 7047 const PetscScalar *flip = flips ? flips[p] : NULL; 7048 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7049 } 7050 break; 7051 default: 7052 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7053 } 7054 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7055 } 7056 } else { 7057 PetscInt dof, off; 7058 const PetscInt **perms = NULL; 7059 const PetscScalar **flips = NULL; 7060 7061 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7062 switch (mode) { 7063 case INSERT_VALUES: 7064 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7065 const PetscInt point = points[2 * p]; 7066 const PetscInt *perm = perms ? perms[p] : NULL; 7067 const PetscScalar *flip = flips ? flips[p] : NULL; 7068 PetscCall(PetscSectionGetDof(section, point, &dof)); 7069 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7070 } 7071 break; 7072 case INSERT_ALL_VALUES: 7073 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7074 const PetscInt point = points[2 * p]; 7075 const PetscInt *perm = perms ? perms[p] : NULL; 7076 const PetscScalar *flip = flips ? flips[p] : NULL; 7077 PetscCall(PetscSectionGetDof(section, point, &dof)); 7078 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7079 } 7080 break; 7081 case INSERT_BC_VALUES: 7082 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7083 const PetscInt point = points[2 * p]; 7084 const PetscInt *perm = perms ? perms[p] : NULL; 7085 const PetscScalar *flip = flips ? flips[p] : NULL; 7086 PetscCall(PetscSectionGetDof(section, point, &dof)); 7087 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7088 } 7089 break; 7090 case ADD_VALUES: 7091 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7092 const PetscInt point = points[2 * p]; 7093 const PetscInt *perm = perms ? perms[p] : NULL; 7094 const PetscScalar *flip = flips ? flips[p] : NULL; 7095 PetscCall(PetscSectionGetDof(section, point, &dof)); 7096 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7097 } 7098 break; 7099 case ADD_ALL_VALUES: 7100 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7101 const PetscInt point = points[2 * p]; 7102 const PetscInt *perm = perms ? perms[p] : NULL; 7103 const PetscScalar *flip = flips ? flips[p] : NULL; 7104 PetscCall(PetscSectionGetDof(section, point, &dof)); 7105 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7106 } 7107 break; 7108 case ADD_BC_VALUES: 7109 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7110 const PetscInt point = points[2 * p]; 7111 const PetscInt *perm = perms ? perms[p] : NULL; 7112 const PetscScalar *flip = flips ? flips[p] : NULL; 7113 PetscCall(PetscSectionGetDof(section, point, &dof)); 7114 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7115 } 7116 break; 7117 default: 7118 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7119 } 7120 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7121 } 7122 /* Cleanup points */ 7123 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7124 /* Cleanup array */ 7125 PetscCall(VecRestoreArray(v, &array)); 7126 PetscFunctionReturn(PETSC_SUCCESS); 7127 } 7128 7129 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7130 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7131 { 7132 PetscFunctionBegin; 7133 *contains = PETSC_TRUE; 7134 if (label) { 7135 PetscInt fdof; 7136 7137 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7138 if (!*contains) { 7139 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7140 *offset += fdof; 7141 PetscFunctionReturn(PETSC_SUCCESS); 7142 } 7143 } 7144 PetscFunctionReturn(PETSC_SUCCESS); 7145 } 7146 7147 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7148 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) 7149 { 7150 PetscSection clSection; 7151 IS clPoints; 7152 PetscScalar *array; 7153 PetscInt *points = NULL; 7154 const PetscInt *clp; 7155 PetscInt numFields, numPoints, p; 7156 PetscInt offset = 0, f; 7157 7158 PetscFunctionBeginHot; 7159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7160 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7161 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7162 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7163 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7164 /* Get points */ 7165 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7166 /* Get array */ 7167 PetscCall(VecGetArray(v, &array)); 7168 /* Get values */ 7169 for (f = 0; f < numFields; ++f) { 7170 const PetscInt **perms = NULL; 7171 const PetscScalar **flips = NULL; 7172 PetscBool contains; 7173 7174 if (!fieldActive[f]) { 7175 for (p = 0; p < numPoints * 2; p += 2) { 7176 PetscInt fdof; 7177 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7178 offset += fdof; 7179 } 7180 continue; 7181 } 7182 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7183 switch (mode) { 7184 case INSERT_VALUES: 7185 for (p = 0; p < numPoints; p++) { 7186 const PetscInt point = points[2 * p]; 7187 const PetscInt *perm = perms ? perms[p] : NULL; 7188 const PetscScalar *flip = flips ? flips[p] : NULL; 7189 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7190 if (!contains) continue; 7191 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7192 } 7193 break; 7194 case INSERT_ALL_VALUES: 7195 for (p = 0; p < numPoints; p++) { 7196 const PetscInt point = points[2 * p]; 7197 const PetscInt *perm = perms ? perms[p] : NULL; 7198 const PetscScalar *flip = flips ? flips[p] : NULL; 7199 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7200 if (!contains) continue; 7201 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7202 } 7203 break; 7204 case INSERT_BC_VALUES: 7205 for (p = 0; p < numPoints; p++) { 7206 const PetscInt point = points[2 * p]; 7207 const PetscInt *perm = perms ? perms[p] : NULL; 7208 const PetscScalar *flip = flips ? flips[p] : NULL; 7209 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7210 if (!contains) continue; 7211 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7212 } 7213 break; 7214 case ADD_VALUES: 7215 for (p = 0; p < numPoints; p++) { 7216 const PetscInt point = points[2 * p]; 7217 const PetscInt *perm = perms ? perms[p] : NULL; 7218 const PetscScalar *flip = flips ? flips[p] : NULL; 7219 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7220 if (!contains) continue; 7221 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7222 } 7223 break; 7224 case ADD_ALL_VALUES: 7225 for (p = 0; p < numPoints; p++) { 7226 const PetscInt point = points[2 * p]; 7227 const PetscInt *perm = perms ? perms[p] : NULL; 7228 const PetscScalar *flip = flips ? flips[p] : NULL; 7229 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7230 if (!contains) continue; 7231 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7232 } 7233 break; 7234 default: 7235 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7236 } 7237 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7238 } 7239 /* Cleanup points */ 7240 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7241 /* Cleanup array */ 7242 PetscCall(VecRestoreArray(v, &array)); 7243 PetscFunctionReturn(PETSC_SUCCESS); 7244 } 7245 7246 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7247 { 7248 PetscMPIInt rank; 7249 PetscInt i, j; 7250 7251 PetscFunctionBegin; 7252 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7253 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7254 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7255 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7256 numCIndices = numCIndices ? numCIndices : numRIndices; 7257 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7258 for (i = 0; i < numRIndices; i++) { 7259 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7260 for (j = 0; j < numCIndices; j++) { 7261 #if defined(PETSC_USE_COMPLEX) 7262 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7263 #else 7264 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7265 #endif 7266 } 7267 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7268 } 7269 PetscFunctionReturn(PETSC_SUCCESS); 7270 } 7271 7272 /* 7273 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7274 7275 Input Parameters: 7276 + section - The section for this data layout 7277 . islocal - Is the section (and thus indices being requested) local or global? 7278 . point - The point contributing dofs with these indices 7279 . off - The global offset of this point 7280 . loff - The local offset of each field 7281 . setBC - The flag determining whether to include indices of boundary values 7282 . perm - A permutation of the dofs on this point, or NULL 7283 - indperm - A permutation of the entire indices array, or NULL 7284 7285 Output Parameter: 7286 . indices - Indices for dofs on this point 7287 7288 Level: developer 7289 7290 Note: The indices could be local or global, depending on the value of 'off'. 7291 */ 7292 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7293 { 7294 PetscInt dof; /* The number of unknowns on this point */ 7295 PetscInt cdof; /* The number of constraints on this point */ 7296 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7297 PetscInt cind = 0, k; 7298 7299 PetscFunctionBegin; 7300 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7301 PetscCall(PetscSectionGetDof(section, point, &dof)); 7302 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7303 if (!cdof || setBC) { 7304 for (k = 0; k < dof; ++k) { 7305 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7306 const PetscInt ind = indperm ? indperm[preind] : preind; 7307 7308 indices[ind] = off + k; 7309 } 7310 } else { 7311 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7312 for (k = 0; k < dof; ++k) { 7313 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7314 const PetscInt ind = indperm ? indperm[preind] : preind; 7315 7316 if ((cind < cdof) && (k == cdofs[cind])) { 7317 /* Insert check for returning constrained indices */ 7318 indices[ind] = -(off + k + 1); 7319 ++cind; 7320 } else { 7321 indices[ind] = off + k - (islocal ? 0 : cind); 7322 } 7323 } 7324 } 7325 *loff += dof; 7326 PetscFunctionReturn(PETSC_SUCCESS); 7327 } 7328 7329 /* 7330 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7331 7332 Input Parameters: 7333 + section - a section (global or local) 7334 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7335 . point - point within section 7336 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7337 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7338 . setBC - identify constrained (boundary condition) points via involution. 7339 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7340 . permsoff - offset 7341 - indperm - index permutation 7342 7343 Output Parameter: 7344 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7345 . indices - array to hold indices (as defined by section) of each dof associated with point 7346 7347 Notes: 7348 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7349 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7350 in the local vector. 7351 7352 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7353 significant). It is invalid to call with a global section and setBC=true. 7354 7355 Developer Note: 7356 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7357 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7358 offset could be obtained from the section instead of passing it explicitly as we do now. 7359 7360 Example: 7361 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7362 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7363 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7364 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. 7365 7366 Level: developer 7367 */ 7368 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[]) 7369 { 7370 PetscInt numFields, foff, f; 7371 7372 PetscFunctionBegin; 7373 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7374 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7375 for (f = 0, foff = 0; f < numFields; ++f) { 7376 PetscInt fdof, cfdof; 7377 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7378 PetscInt cind = 0, b; 7379 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7380 7381 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7382 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7383 if (!cfdof || setBC) { 7384 for (b = 0; b < fdof; ++b) { 7385 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7386 const PetscInt ind = indperm ? indperm[preind] : preind; 7387 7388 indices[ind] = off + foff + b; 7389 } 7390 } else { 7391 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7392 for (b = 0; b < fdof; ++b) { 7393 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7394 const PetscInt ind = indperm ? indperm[preind] : preind; 7395 7396 if ((cind < cfdof) && (b == fcdofs[cind])) { 7397 indices[ind] = -(off + foff + b + 1); 7398 ++cind; 7399 } else { 7400 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7401 } 7402 } 7403 } 7404 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7405 foffs[f] += fdof; 7406 } 7407 PetscFunctionReturn(PETSC_SUCCESS); 7408 } 7409 7410 /* 7411 This version believes the globalSection offsets for each field, rather than just the point offset 7412 7413 . foffs - The offset into 'indices' for each field, since it is segregated by field 7414 7415 Notes: 7416 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7417 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7418 */ 7419 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7420 { 7421 PetscInt numFields, foff, f; 7422 7423 PetscFunctionBegin; 7424 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7425 for (f = 0; f < numFields; ++f) { 7426 PetscInt fdof, cfdof; 7427 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7428 PetscInt cind = 0, b; 7429 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7430 7431 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7432 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7433 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7434 if (!cfdof) { 7435 for (b = 0; b < fdof; ++b) { 7436 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7437 const PetscInt ind = indperm ? indperm[preind] : preind; 7438 7439 indices[ind] = foff + b; 7440 } 7441 } else { 7442 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7443 for (b = 0; b < fdof; ++b) { 7444 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7445 const PetscInt ind = indperm ? indperm[preind] : preind; 7446 7447 if ((cind < cfdof) && (b == fcdofs[cind])) { 7448 indices[ind] = -(foff + b + 1); 7449 ++cind; 7450 } else { 7451 indices[ind] = foff + b - cind; 7452 } 7453 } 7454 } 7455 foffs[f] += fdof; 7456 } 7457 PetscFunctionReturn(PETSC_SUCCESS); 7458 } 7459 7460 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) 7461 { 7462 Mat cMat; 7463 PetscSection aSec, cSec; 7464 IS aIS; 7465 PetscInt aStart = -1, aEnd = -1; 7466 const PetscInt *anchors; 7467 PetscInt numFields, f, p, q, newP = 0; 7468 PetscInt newNumPoints = 0, newNumIndices = 0; 7469 PetscInt *newPoints, *indices, *newIndices; 7470 PetscInt maxAnchor, maxDof; 7471 PetscInt newOffsets[32]; 7472 PetscInt *pointMatOffsets[32]; 7473 PetscInt *newPointOffsets[32]; 7474 PetscScalar *pointMat[32]; 7475 PetscScalar *newValues = NULL, *tmpValues; 7476 PetscBool anyConstrained = PETSC_FALSE; 7477 7478 PetscFunctionBegin; 7479 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7480 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7481 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7482 7483 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7484 /* if there are point-to-point constraints */ 7485 if (aSec) { 7486 PetscCall(PetscArrayzero(newOffsets, 32)); 7487 PetscCall(ISGetIndices(aIS, &anchors)); 7488 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7489 /* figure out how many points are going to be in the new element matrix 7490 * (we allow double counting, because it's all just going to be summed 7491 * into the global matrix anyway) */ 7492 for (p = 0; p < 2 * numPoints; p += 2) { 7493 PetscInt b = points[p]; 7494 PetscInt bDof = 0, bSecDof; 7495 7496 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7497 if (!bSecDof) continue; 7498 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7499 if (bDof) { 7500 /* this point is constrained */ 7501 /* it is going to be replaced by its anchors */ 7502 PetscInt bOff, q; 7503 7504 anyConstrained = PETSC_TRUE; 7505 newNumPoints += bDof; 7506 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7507 for (q = 0; q < bDof; q++) { 7508 PetscInt a = anchors[bOff + q]; 7509 PetscInt aDof; 7510 7511 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7512 newNumIndices += aDof; 7513 for (f = 0; f < numFields; ++f) { 7514 PetscInt fDof; 7515 7516 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7517 newOffsets[f + 1] += fDof; 7518 } 7519 } 7520 } else { 7521 /* this point is not constrained */ 7522 newNumPoints++; 7523 newNumIndices += bSecDof; 7524 for (f = 0; f < numFields; ++f) { 7525 PetscInt fDof; 7526 7527 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7528 newOffsets[f + 1] += fDof; 7529 } 7530 } 7531 } 7532 } 7533 if (!anyConstrained) { 7534 if (outNumPoints) *outNumPoints = 0; 7535 if (outNumIndices) *outNumIndices = 0; 7536 if (outPoints) *outPoints = NULL; 7537 if (outValues) *outValues = NULL; 7538 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7539 PetscFunctionReturn(PETSC_SUCCESS); 7540 } 7541 7542 if (outNumPoints) *outNumPoints = newNumPoints; 7543 if (outNumIndices) *outNumIndices = newNumIndices; 7544 7545 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7546 7547 if (!outPoints && !outValues) { 7548 if (offsets) { 7549 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7550 } 7551 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7552 PetscFunctionReturn(PETSC_SUCCESS); 7553 } 7554 7555 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7556 7557 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7558 7559 /* workspaces */ 7560 if (numFields) { 7561 for (f = 0; f < numFields; f++) { 7562 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7563 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7564 } 7565 } else { 7566 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7567 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7568 } 7569 7570 /* get workspaces for the point-to-point matrices */ 7571 if (numFields) { 7572 PetscInt totalOffset, totalMatOffset; 7573 7574 for (p = 0; p < numPoints; p++) { 7575 PetscInt b = points[2 * p]; 7576 PetscInt bDof = 0, bSecDof; 7577 7578 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7579 if (!bSecDof) { 7580 for (f = 0; f < numFields; f++) { 7581 newPointOffsets[f][p + 1] = 0; 7582 pointMatOffsets[f][p + 1] = 0; 7583 } 7584 continue; 7585 } 7586 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7587 if (bDof) { 7588 for (f = 0; f < numFields; f++) { 7589 PetscInt fDof, q, bOff, allFDof = 0; 7590 7591 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7592 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7593 for (q = 0; q < bDof; q++) { 7594 PetscInt a = anchors[bOff + q]; 7595 PetscInt aFDof; 7596 7597 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7598 allFDof += aFDof; 7599 } 7600 newPointOffsets[f][p + 1] = allFDof; 7601 pointMatOffsets[f][p + 1] = fDof * allFDof; 7602 } 7603 } else { 7604 for (f = 0; f < numFields; f++) { 7605 PetscInt fDof; 7606 7607 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7608 newPointOffsets[f][p + 1] = fDof; 7609 pointMatOffsets[f][p + 1] = 0; 7610 } 7611 } 7612 } 7613 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7614 newPointOffsets[f][0] = totalOffset; 7615 pointMatOffsets[f][0] = totalMatOffset; 7616 for (p = 0; p < numPoints; p++) { 7617 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7618 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7619 } 7620 totalOffset = newPointOffsets[f][numPoints]; 7621 totalMatOffset = pointMatOffsets[f][numPoints]; 7622 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7623 } 7624 } else { 7625 for (p = 0; p < numPoints; p++) { 7626 PetscInt b = points[2 * p]; 7627 PetscInt bDof = 0, bSecDof; 7628 7629 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7630 if (!bSecDof) { 7631 newPointOffsets[0][p + 1] = 0; 7632 pointMatOffsets[0][p + 1] = 0; 7633 continue; 7634 } 7635 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7636 if (bDof) { 7637 PetscInt bOff, q, allDof = 0; 7638 7639 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7640 for (q = 0; q < bDof; q++) { 7641 PetscInt a = anchors[bOff + q], aDof; 7642 7643 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7644 allDof += aDof; 7645 } 7646 newPointOffsets[0][p + 1] = allDof; 7647 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7648 } else { 7649 newPointOffsets[0][p + 1] = bSecDof; 7650 pointMatOffsets[0][p + 1] = 0; 7651 } 7652 } 7653 newPointOffsets[0][0] = 0; 7654 pointMatOffsets[0][0] = 0; 7655 for (p = 0; p < numPoints; p++) { 7656 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7657 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7658 } 7659 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7660 } 7661 7662 /* output arrays */ 7663 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7664 7665 /* get the point-to-point matrices; construct newPoints */ 7666 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7667 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7668 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7669 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7670 if (numFields) { 7671 for (p = 0, newP = 0; p < numPoints; p++) { 7672 PetscInt b = points[2 * p]; 7673 PetscInt o = points[2 * p + 1]; 7674 PetscInt bDof = 0, bSecDof; 7675 7676 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7677 if (!bSecDof) continue; 7678 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7679 if (bDof) { 7680 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7681 7682 fStart[0] = 0; 7683 fEnd[0] = 0; 7684 for (f = 0; f < numFields; f++) { 7685 PetscInt fDof; 7686 7687 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7688 fStart[f + 1] = fStart[f] + fDof; 7689 fEnd[f + 1] = fStart[f + 1]; 7690 } 7691 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7692 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7693 7694 fAnchorStart[0] = 0; 7695 fAnchorEnd[0] = 0; 7696 for (f = 0; f < numFields; f++) { 7697 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7698 7699 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7700 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7701 } 7702 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7703 for (q = 0; q < bDof; q++) { 7704 PetscInt a = anchors[bOff + q], aOff; 7705 7706 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7707 newPoints[2 * (newP + q)] = a; 7708 newPoints[2 * (newP + q) + 1] = 0; 7709 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7710 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7711 } 7712 newP += bDof; 7713 7714 if (outValues) { 7715 /* get the point-to-point submatrix */ 7716 for (f = 0; f < numFields; f++) PetscCall(MatGetValues(cMat, fEnd[f] - fStart[f], indices + fStart[f], fAnchorEnd[f] - fAnchorStart[f], newIndices + fAnchorStart[f], pointMat[f] + pointMatOffsets[f][p])); 7717 } 7718 } else { 7719 newPoints[2 * newP] = b; 7720 newPoints[2 * newP + 1] = o; 7721 newP++; 7722 } 7723 } 7724 } else { 7725 for (p = 0; p < numPoints; p++) { 7726 PetscInt b = points[2 * p]; 7727 PetscInt o = points[2 * p + 1]; 7728 PetscInt bDof = 0, bSecDof; 7729 7730 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7731 if (!bSecDof) continue; 7732 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7733 if (bDof) { 7734 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7735 7736 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7737 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7738 7739 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7740 for (q = 0; q < bDof; q++) { 7741 PetscInt a = anchors[bOff + q], aOff; 7742 7743 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7744 7745 newPoints[2 * (newP + q)] = a; 7746 newPoints[2 * (newP + q) + 1] = 0; 7747 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7748 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7749 } 7750 newP += bDof; 7751 7752 /* get the point-to-point submatrix */ 7753 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7754 } else { 7755 newPoints[2 * newP] = b; 7756 newPoints[2 * newP + 1] = o; 7757 newP++; 7758 } 7759 } 7760 } 7761 7762 if (outValues) { 7763 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7764 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7765 /* multiply constraints on the right */ 7766 if (numFields) { 7767 for (f = 0; f < numFields; f++) { 7768 PetscInt oldOff = offsets[f]; 7769 7770 for (p = 0; p < numPoints; p++) { 7771 PetscInt cStart = newPointOffsets[f][p]; 7772 PetscInt b = points[2 * p]; 7773 PetscInt c, r, k; 7774 PetscInt dof; 7775 7776 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7777 if (!dof) continue; 7778 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7779 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7780 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7781 7782 for (r = 0; r < numIndices; r++) { 7783 for (c = 0; c < nCols; c++) { 7784 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7785 } 7786 } 7787 } else { 7788 /* copy this column as is */ 7789 for (r = 0; r < numIndices; r++) { 7790 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7791 } 7792 } 7793 oldOff += dof; 7794 } 7795 } 7796 } else { 7797 PetscInt oldOff = 0; 7798 for (p = 0; p < numPoints; p++) { 7799 PetscInt cStart = newPointOffsets[0][p]; 7800 PetscInt b = points[2 * p]; 7801 PetscInt c, r, k; 7802 PetscInt dof; 7803 7804 PetscCall(PetscSectionGetDof(section, b, &dof)); 7805 if (!dof) continue; 7806 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7807 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7808 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7809 7810 for (r = 0; r < numIndices; r++) { 7811 for (c = 0; c < nCols; c++) { 7812 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7813 } 7814 } 7815 } else { 7816 /* copy this column as is */ 7817 for (r = 0; r < numIndices; r++) { 7818 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7819 } 7820 } 7821 oldOff += dof; 7822 } 7823 } 7824 7825 if (multiplyLeft) { 7826 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7827 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7828 /* multiply constraints transpose on the left */ 7829 if (numFields) { 7830 for (f = 0; f < numFields; f++) { 7831 PetscInt oldOff = offsets[f]; 7832 7833 for (p = 0; p < numPoints; p++) { 7834 PetscInt rStart = newPointOffsets[f][p]; 7835 PetscInt b = points[2 * p]; 7836 PetscInt c, r, k; 7837 PetscInt dof; 7838 7839 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7840 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7841 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7842 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7843 7844 for (r = 0; r < nRows; r++) { 7845 for (c = 0; c < newNumIndices; c++) { 7846 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7847 } 7848 } 7849 } else { 7850 /* copy this row as is */ 7851 for (r = 0; r < dof; r++) { 7852 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7853 } 7854 } 7855 oldOff += dof; 7856 } 7857 } 7858 } else { 7859 PetscInt oldOff = 0; 7860 7861 for (p = 0; p < numPoints; p++) { 7862 PetscInt rStart = newPointOffsets[0][p]; 7863 PetscInt b = points[2 * p]; 7864 PetscInt c, r, k; 7865 PetscInt dof; 7866 7867 PetscCall(PetscSectionGetDof(section, b, &dof)); 7868 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7869 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7870 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7871 7872 for (r = 0; r < nRows; r++) { 7873 for (c = 0; c < newNumIndices; c++) { 7874 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7875 } 7876 } 7877 } else { 7878 /* copy this row as is */ 7879 for (r = 0; r < dof; r++) { 7880 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7881 } 7882 } 7883 oldOff += dof; 7884 } 7885 } 7886 7887 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7888 } else { 7889 newValues = tmpValues; 7890 } 7891 } 7892 7893 /* clean up */ 7894 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7895 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7896 7897 if (numFields) { 7898 for (f = 0; f < numFields; f++) { 7899 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7900 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7901 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7902 } 7903 } else { 7904 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7905 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7906 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7907 } 7908 PetscCall(ISRestoreIndices(aIS, &anchors)); 7909 7910 /* output */ 7911 if (outPoints) { 7912 *outPoints = newPoints; 7913 } else { 7914 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7915 } 7916 if (outValues) *outValues = newValues; 7917 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7918 PetscFunctionReturn(PETSC_SUCCESS); 7919 } 7920 7921 /*@C 7922 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7923 7924 Not collective 7925 7926 Input Parameters: 7927 + dm - The `DM` 7928 . section - The `PetscSection` describing the points (a local section) 7929 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7930 . point - The point defining the closure 7931 - useClPerm - Use the closure point permutation if available 7932 7933 Output Parameters: 7934 + numIndices - The number of dof indices in the closure of point with the input sections 7935 . indices - The dof indices 7936 . outOffsets - Array to write the field offsets into, or `NULL` 7937 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7938 7939 Level: advanced 7940 7941 Notes: 7942 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7943 7944 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7945 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7946 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7947 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7948 indices (with the above semantics) are implied. 7949 7950 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7951 `PetscSection`, `DMGetGlobalSection()` 7952 @*/ 7953 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7954 { 7955 /* Closure ordering */ 7956 PetscSection clSection; 7957 IS clPoints; 7958 const PetscInt *clp; 7959 PetscInt *points; 7960 const PetscInt *clperm = NULL; 7961 /* Dof permutation and sign flips */ 7962 const PetscInt **perms[32] = {NULL}; 7963 const PetscScalar **flips[32] = {NULL}; 7964 PetscScalar *valCopy = NULL; 7965 /* Hanging node constraints */ 7966 PetscInt *pointsC = NULL; 7967 PetscScalar *valuesC = NULL; 7968 PetscInt NclC, NiC; 7969 7970 PetscInt *idx; 7971 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7972 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7973 7974 PetscFunctionBeginHot; 7975 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7976 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7977 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7978 if (numIndices) PetscAssertPointer(numIndices, 6); 7979 if (indices) PetscAssertPointer(indices, 7); 7980 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7981 if (values) PetscAssertPointer(values, 9); 7982 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7983 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7984 PetscCall(PetscArrayzero(offsets, 32)); 7985 /* 1) Get points in closure */ 7986 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7987 if (useClPerm) { 7988 PetscInt depth, clsize; 7989 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7990 for (clsize = 0, p = 0; p < Ncl; p++) { 7991 PetscInt dof; 7992 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7993 clsize += dof; 7994 } 7995 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7996 } 7997 /* 2) Get number of indices on these points and field offsets from section */ 7998 for (p = 0; p < Ncl * 2; p += 2) { 7999 PetscInt dof, fdof; 8000 8001 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8002 for (f = 0; f < Nf; ++f) { 8003 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8004 offsets[f + 1] += fdof; 8005 } 8006 Ni += dof; 8007 } 8008 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8009 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8010 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8011 for (f = 0; f < PetscMax(1, Nf); ++f) { 8012 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8013 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8014 /* may need to apply sign changes to the element matrix */ 8015 if (values && flips[f]) { 8016 PetscInt foffset = offsets[f]; 8017 8018 for (p = 0; p < Ncl; ++p) { 8019 PetscInt pnt = points[2 * p], fdof; 8020 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8021 8022 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8023 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8024 if (flip) { 8025 PetscInt i, j, k; 8026 8027 if (!valCopy) { 8028 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8029 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8030 *values = valCopy; 8031 } 8032 for (i = 0; i < fdof; ++i) { 8033 PetscScalar fval = flip[i]; 8034 8035 for (k = 0; k < Ni; ++k) { 8036 valCopy[Ni * (foffset + i) + k] *= fval; 8037 valCopy[Ni * k + (foffset + i)] *= fval; 8038 } 8039 } 8040 } 8041 foffset += fdof; 8042 } 8043 } 8044 } 8045 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8046 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 8047 if (NclC) { 8048 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8049 for (f = 0; f < PetscMax(1, Nf); ++f) { 8050 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8051 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8052 } 8053 for (f = 0; f < PetscMax(1, Nf); ++f) { 8054 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8055 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8056 } 8057 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8058 Ncl = NclC; 8059 Ni = NiC; 8060 points = pointsC; 8061 if (values) *values = valuesC; 8062 } 8063 /* 5) Calculate indices */ 8064 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8065 if (Nf) { 8066 PetscInt idxOff; 8067 PetscBool useFieldOffsets; 8068 8069 if (outOffsets) { 8070 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8071 } 8072 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8073 if (useFieldOffsets) { 8074 for (p = 0; p < Ncl; ++p) { 8075 const PetscInt pnt = points[p * 2]; 8076 8077 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8078 } 8079 } else { 8080 for (p = 0; p < Ncl; ++p) { 8081 const PetscInt pnt = points[p * 2]; 8082 8083 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8084 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8085 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8086 * global section. */ 8087 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8088 } 8089 } 8090 } else { 8091 PetscInt off = 0, idxOff; 8092 8093 for (p = 0; p < Ncl; ++p) { 8094 const PetscInt pnt = points[p * 2]; 8095 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8096 8097 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8098 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8099 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8100 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8101 } 8102 } 8103 /* 6) Cleanup */ 8104 for (f = 0; f < PetscMax(1, Nf); ++f) { 8105 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8106 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8107 } 8108 if (NclC) { 8109 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8110 } else { 8111 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8112 } 8113 8114 if (numIndices) *numIndices = Ni; 8115 if (indices) *indices = idx; 8116 PetscFunctionReturn(PETSC_SUCCESS); 8117 } 8118 8119 /*@C 8120 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8121 8122 Not collective 8123 8124 Input Parameters: 8125 + dm - The `DM` 8126 . section - The `PetscSection` describing the points (a local section) 8127 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8128 . point - The point defining the closure 8129 - useClPerm - Use the closure point permutation if available 8130 8131 Output Parameters: 8132 + numIndices - The number of dof indices in the closure of point with the input sections 8133 . indices - The dof indices 8134 . outOffsets - Array to write the field offsets into, or `NULL` 8135 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8136 8137 Level: advanced 8138 8139 Notes: 8140 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8141 8142 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8143 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8144 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8145 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8146 indices (with the above semantics) are implied. 8147 8148 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8149 @*/ 8150 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8151 { 8152 PetscFunctionBegin; 8153 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8154 PetscAssertPointer(indices, 7); 8155 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8156 PetscFunctionReturn(PETSC_SUCCESS); 8157 } 8158 8159 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8160 { 8161 DM_Plex *mesh = (DM_Plex *)dm->data; 8162 PetscInt *indices; 8163 PetscInt numIndices; 8164 const PetscScalar *valuesOrig = values; 8165 PetscErrorCode ierr; 8166 8167 PetscFunctionBegin; 8168 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8169 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8170 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8171 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8172 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8173 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8174 8175 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8176 8177 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8178 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8179 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8180 if (ierr) { 8181 PetscMPIInt rank; 8182 8183 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8184 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8185 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8186 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8187 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8188 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8189 } 8190 if (mesh->printFEM > 1) { 8191 PetscInt i; 8192 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8193 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8194 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8195 } 8196 8197 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8198 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8199 PetscFunctionReturn(PETSC_SUCCESS); 8200 } 8201 8202 /*@C 8203 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8204 8205 Not collective 8206 8207 Input Parameters: 8208 + dm - The `DM` 8209 . section - The section describing the layout in `v`, or `NULL` to use the default section 8210 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8211 . A - The matrix 8212 . point - The point in the `DM` 8213 . values - The array of values 8214 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8215 8216 Level: intermediate 8217 8218 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8219 @*/ 8220 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8221 { 8222 PetscFunctionBegin; 8223 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8224 PetscFunctionReturn(PETSC_SUCCESS); 8225 } 8226 8227 /*@C 8228 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8229 8230 Not collective 8231 8232 Input Parameters: 8233 + dmRow - The `DM` for the row fields 8234 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8235 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8236 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8237 . dmCol - The `DM` for the column fields 8238 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8239 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8240 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8241 . A - The matrix 8242 . point - The point in the `DM` 8243 . values - The array of values 8244 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8245 8246 Level: intermediate 8247 8248 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8249 @*/ 8250 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) 8251 { 8252 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8253 PetscInt *indicesRow, *indicesCol; 8254 PetscInt numIndicesRow, numIndicesCol; 8255 const PetscScalar *valuesOrig = values; 8256 PetscErrorCode ierr; 8257 8258 PetscFunctionBegin; 8259 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8260 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8261 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8262 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8263 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8264 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8265 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8266 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8267 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8268 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8269 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8270 8271 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8272 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8273 8274 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8275 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8276 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 8277 if (ierr) { 8278 PetscMPIInt rank; 8279 8280 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8281 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8282 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8283 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8284 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 8285 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8286 } 8287 8288 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8289 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8290 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8291 PetscFunctionReturn(PETSC_SUCCESS); 8292 } 8293 8294 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8295 { 8296 DM_Plex *mesh = (DM_Plex *)dmf->data; 8297 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8298 PetscInt *cpoints = NULL; 8299 PetscInt *findices, *cindices; 8300 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8301 PetscInt foffsets[32], coffsets[32]; 8302 DMPolytopeType ct; 8303 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8304 PetscErrorCode ierr; 8305 8306 PetscFunctionBegin; 8307 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8308 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8309 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8310 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8311 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8312 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8313 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8314 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8315 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8316 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8317 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8318 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8319 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8320 PetscCall(PetscArrayzero(foffsets, 32)); 8321 PetscCall(PetscArrayzero(coffsets, 32)); 8322 /* Column indices */ 8323 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8324 maxFPoints = numCPoints; 8325 /* Compress out points not in the section */ 8326 /* TODO: Squeeze out points with 0 dof as well */ 8327 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8328 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8329 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8330 cpoints[q * 2] = cpoints[p]; 8331 cpoints[q * 2 + 1] = cpoints[p + 1]; 8332 ++q; 8333 } 8334 } 8335 numCPoints = q; 8336 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8337 PetscInt fdof; 8338 8339 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8340 if (!dof) continue; 8341 for (f = 0; f < numFields; ++f) { 8342 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8343 coffsets[f + 1] += fdof; 8344 } 8345 numCIndices += dof; 8346 } 8347 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8348 /* Row indices */ 8349 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8350 { 8351 DMPlexTransform tr; 8352 DMPolytopeType *rct; 8353 PetscInt *rsize, *rcone, *rornt, Nt; 8354 8355 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8356 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8357 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8358 numSubcells = rsize[Nt - 1]; 8359 PetscCall(DMPlexTransformDestroy(&tr)); 8360 } 8361 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8362 for (r = 0, q = 0; r < numSubcells; ++r) { 8363 /* TODO Map from coarse to fine cells */ 8364 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8365 /* Compress out points not in the section */ 8366 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8367 for (p = 0; p < numFPoints * 2; p += 2) { 8368 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8369 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8370 if (!dof) continue; 8371 for (s = 0; s < q; ++s) 8372 if (fpoints[p] == ftotpoints[s * 2]) break; 8373 if (s < q) continue; 8374 ftotpoints[q * 2] = fpoints[p]; 8375 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8376 ++q; 8377 } 8378 } 8379 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8380 } 8381 numFPoints = q; 8382 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8383 PetscInt fdof; 8384 8385 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8386 if (!dof) continue; 8387 for (f = 0; f < numFields; ++f) { 8388 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8389 foffsets[f + 1] += fdof; 8390 } 8391 numFIndices += dof; 8392 } 8393 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8394 8395 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8396 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8397 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8398 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8399 if (numFields) { 8400 const PetscInt **permsF[32] = {NULL}; 8401 const PetscInt **permsC[32] = {NULL}; 8402 8403 for (f = 0; f < numFields; f++) { 8404 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8405 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8406 } 8407 for (p = 0; p < numFPoints; p++) { 8408 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8409 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8410 } 8411 for (p = 0; p < numCPoints; p++) { 8412 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8413 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8414 } 8415 for (f = 0; f < numFields; f++) { 8416 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8417 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8418 } 8419 } else { 8420 const PetscInt **permsF = NULL; 8421 const PetscInt **permsC = NULL; 8422 8423 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8424 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8425 for (p = 0, off = 0; p < numFPoints; p++) { 8426 const PetscInt *perm = permsF ? permsF[p] : NULL; 8427 8428 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8429 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8430 } 8431 for (p = 0, off = 0; p < numCPoints; p++) { 8432 const PetscInt *perm = permsC ? permsC[p] : NULL; 8433 8434 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8435 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8436 } 8437 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8438 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8439 } 8440 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8441 /* TODO: flips */ 8442 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8443 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8444 if (ierr) { 8445 PetscMPIInt rank; 8446 8447 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8448 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8449 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8450 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8451 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8452 } 8453 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8454 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8455 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8456 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8457 PetscFunctionReturn(PETSC_SUCCESS); 8458 } 8459 8460 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8461 { 8462 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8463 PetscInt *cpoints = NULL; 8464 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8465 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8466 DMPolytopeType ct; 8467 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8468 8469 PetscFunctionBegin; 8470 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8471 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8472 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8473 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8474 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8475 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8476 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8477 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8478 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8479 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8480 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8481 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8482 /* Column indices */ 8483 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8484 maxFPoints = numCPoints; 8485 /* Compress out points not in the section */ 8486 /* TODO: Squeeze out points with 0 dof as well */ 8487 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8488 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8489 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8490 cpoints[q * 2] = cpoints[p]; 8491 cpoints[q * 2 + 1] = cpoints[p + 1]; 8492 ++q; 8493 } 8494 } 8495 numCPoints = q; 8496 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8497 PetscInt fdof; 8498 8499 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8500 if (!dof) continue; 8501 for (f = 0; f < numFields; ++f) { 8502 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8503 coffsets[f + 1] += fdof; 8504 } 8505 numCIndices += dof; 8506 } 8507 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8508 /* Row indices */ 8509 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8510 { 8511 DMPlexTransform tr; 8512 DMPolytopeType *rct; 8513 PetscInt *rsize, *rcone, *rornt, Nt; 8514 8515 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8516 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8517 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8518 numSubcells = rsize[Nt - 1]; 8519 PetscCall(DMPlexTransformDestroy(&tr)); 8520 } 8521 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8522 for (r = 0, q = 0; r < numSubcells; ++r) { 8523 /* TODO Map from coarse to fine cells */ 8524 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8525 /* Compress out points not in the section */ 8526 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8527 for (p = 0; p < numFPoints * 2; p += 2) { 8528 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8529 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8530 if (!dof) continue; 8531 for (s = 0; s < q; ++s) 8532 if (fpoints[p] == ftotpoints[s * 2]) break; 8533 if (s < q) continue; 8534 ftotpoints[q * 2] = fpoints[p]; 8535 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8536 ++q; 8537 } 8538 } 8539 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8540 } 8541 numFPoints = q; 8542 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8543 PetscInt fdof; 8544 8545 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8546 if (!dof) continue; 8547 for (f = 0; f < numFields; ++f) { 8548 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8549 foffsets[f + 1] += fdof; 8550 } 8551 numFIndices += dof; 8552 } 8553 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8554 8555 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8556 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8557 if (numFields) { 8558 const PetscInt **permsF[32] = {NULL}; 8559 const PetscInt **permsC[32] = {NULL}; 8560 8561 for (f = 0; f < numFields; f++) { 8562 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8563 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8564 } 8565 for (p = 0; p < numFPoints; p++) { 8566 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8567 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8568 } 8569 for (p = 0; p < numCPoints; p++) { 8570 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8571 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8572 } 8573 for (f = 0; f < numFields; f++) { 8574 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8575 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8576 } 8577 } else { 8578 const PetscInt **permsF = NULL; 8579 const PetscInt **permsC = NULL; 8580 8581 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8582 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8583 for (p = 0, off = 0; p < numFPoints; p++) { 8584 const PetscInt *perm = permsF ? permsF[p] : NULL; 8585 8586 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8587 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8588 } 8589 for (p = 0, off = 0; p < numCPoints; p++) { 8590 const PetscInt *perm = permsC ? permsC[p] : NULL; 8591 8592 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8593 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8594 } 8595 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8596 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8597 } 8598 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8599 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8600 PetscFunctionReturn(PETSC_SUCCESS); 8601 } 8602 8603 /*@C 8604 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8605 8606 Input Parameter: 8607 . dm - The `DMPLEX` object 8608 8609 Output Parameter: 8610 . cellHeight - The height of a cell 8611 8612 Level: developer 8613 8614 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8615 @*/ 8616 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8617 { 8618 DM_Plex *mesh = (DM_Plex *)dm->data; 8619 8620 PetscFunctionBegin; 8621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8622 PetscAssertPointer(cellHeight, 2); 8623 *cellHeight = mesh->vtkCellHeight; 8624 PetscFunctionReturn(PETSC_SUCCESS); 8625 } 8626 8627 /*@C 8628 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8629 8630 Input Parameters: 8631 + dm - The `DMPLEX` object 8632 - cellHeight - The height of a cell 8633 8634 Level: developer 8635 8636 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8637 @*/ 8638 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8639 { 8640 DM_Plex *mesh = (DM_Plex *)dm->data; 8641 8642 PetscFunctionBegin; 8643 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8644 mesh->vtkCellHeight = cellHeight; 8645 PetscFunctionReturn(PETSC_SUCCESS); 8646 } 8647 8648 /*@ 8649 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8650 8651 Input Parameters: 8652 + dm - The `DMPLEX` object 8653 - ct - The `DMPolytopeType` of the cell 8654 8655 Output Parameters: 8656 + start - The first cell of this type, or `NULL` 8657 - end - The upper bound on this celltype, or `NULL` 8658 8659 Level: advanced 8660 8661 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8662 @*/ 8663 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8664 { 8665 DM_Plex *mesh = (DM_Plex *)dm->data; 8666 DMLabel label; 8667 PetscInt pStart, pEnd; 8668 8669 PetscFunctionBegin; 8670 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8671 if (start) { 8672 PetscAssertPointer(start, 3); 8673 *start = 0; 8674 } 8675 if (end) { 8676 PetscAssertPointer(end, 4); 8677 *end = 0; 8678 } 8679 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8680 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8681 if (mesh->tr) { 8682 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8683 } else { 8684 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8685 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8686 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8687 } 8688 PetscFunctionReturn(PETSC_SUCCESS); 8689 } 8690 8691 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8692 { 8693 PetscSection section, globalSection; 8694 PetscInt *numbers, p; 8695 8696 PetscFunctionBegin; 8697 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8698 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8699 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8700 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8701 PetscCall(PetscSectionSetUp(section)); 8702 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8703 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8704 for (p = pStart; p < pEnd; ++p) { 8705 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8706 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8707 else numbers[p - pStart] += shift; 8708 } 8709 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8710 if (globalSize) { 8711 PetscLayout layout; 8712 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8713 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8714 PetscCall(PetscLayoutDestroy(&layout)); 8715 } 8716 PetscCall(PetscSectionDestroy(§ion)); 8717 PetscCall(PetscSectionDestroy(&globalSection)); 8718 PetscFunctionReturn(PETSC_SUCCESS); 8719 } 8720 8721 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8722 { 8723 PetscInt cellHeight, cStart, cEnd; 8724 8725 PetscFunctionBegin; 8726 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8727 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8728 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8729 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8730 PetscFunctionReturn(PETSC_SUCCESS); 8731 } 8732 8733 /*@ 8734 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8735 8736 Input Parameter: 8737 . dm - The `DMPLEX` object 8738 8739 Output Parameter: 8740 . globalCellNumbers - Global cell numbers for all cells on this process 8741 8742 Level: developer 8743 8744 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8745 @*/ 8746 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8747 { 8748 DM_Plex *mesh = (DM_Plex *)dm->data; 8749 8750 PetscFunctionBegin; 8751 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8752 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8753 *globalCellNumbers = mesh->globalCellNumbers; 8754 PetscFunctionReturn(PETSC_SUCCESS); 8755 } 8756 8757 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8758 { 8759 PetscInt vStart, vEnd; 8760 8761 PetscFunctionBegin; 8762 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8763 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8764 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8765 PetscFunctionReturn(PETSC_SUCCESS); 8766 } 8767 8768 /*@ 8769 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8770 8771 Input Parameter: 8772 . dm - The `DMPLEX` object 8773 8774 Output Parameter: 8775 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8776 8777 Level: developer 8778 8779 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8780 @*/ 8781 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8782 { 8783 DM_Plex *mesh = (DM_Plex *)dm->data; 8784 8785 PetscFunctionBegin; 8786 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8787 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8788 *globalVertexNumbers = mesh->globalVertexNumbers; 8789 PetscFunctionReturn(PETSC_SUCCESS); 8790 } 8791 8792 /*@ 8793 DMPlexCreatePointNumbering - Create a global numbering for all points. 8794 8795 Collective 8796 8797 Input Parameter: 8798 . dm - The `DMPLEX` object 8799 8800 Output Parameter: 8801 . globalPointNumbers - Global numbers for all points on this process 8802 8803 Level: developer 8804 8805 Notes: 8806 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8807 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8808 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8809 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8810 8811 The partitioned mesh is 8812 ``` 8813 (2)--0--(3)--1--(4) (1)--0--(2) 8814 ``` 8815 and its global numbering is 8816 ``` 8817 (3)--0--(4)--1--(5)--2--(6) 8818 ``` 8819 Then the global numbering is provided as 8820 ``` 8821 [0] Number of indices in set 5 8822 [0] 0 0 8823 [0] 1 1 8824 [0] 2 3 8825 [0] 3 4 8826 [0] 4 -6 8827 [1] Number of indices in set 3 8828 [1] 0 2 8829 [1] 1 5 8830 [1] 2 6 8831 ``` 8832 8833 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8834 @*/ 8835 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8836 { 8837 IS nums[4]; 8838 PetscInt depths[4], gdepths[4], starts[4]; 8839 PetscInt depth, d, shift = 0; 8840 PetscBool empty = PETSC_FALSE; 8841 8842 PetscFunctionBegin; 8843 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8844 PetscCall(DMPlexGetDepth(dm, &depth)); 8845 // For unstratified meshes use dim instead of depth 8846 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8847 // If any stratum is empty, we must mark all empty 8848 for (d = 0; d <= depth; ++d) { 8849 PetscInt end; 8850 8851 depths[d] = depth - d; 8852 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8853 if (!(starts[d] - end)) empty = PETSC_TRUE; 8854 } 8855 if (empty) 8856 for (d = 0; d <= depth; ++d) { 8857 depths[d] = -1; 8858 starts[d] = -1; 8859 } 8860 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8861 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8862 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]); 8863 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8864 for (d = 0; d <= depth; ++d) { 8865 PetscInt pStart, pEnd, gsize; 8866 8867 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8868 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8869 shift += gsize; 8870 } 8871 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8872 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8873 PetscFunctionReturn(PETSC_SUCCESS); 8874 } 8875 8876 /*@ 8877 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8878 8879 Input Parameter: 8880 . dm - The `DMPLEX` object 8881 8882 Output Parameter: 8883 . ranks - The rank field 8884 8885 Options Database Key: 8886 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8887 8888 Level: intermediate 8889 8890 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8891 @*/ 8892 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8893 { 8894 DM rdm; 8895 PetscFE fe; 8896 PetscScalar *r; 8897 PetscMPIInt rank; 8898 DMPolytopeType ct; 8899 PetscInt dim, cStart, cEnd, c; 8900 PetscBool simplex; 8901 8902 PetscFunctionBeginUser; 8903 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8904 PetscAssertPointer(ranks, 2); 8905 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8906 PetscCall(DMClone(dm, &rdm)); 8907 PetscCall(DMGetDimension(rdm, &dim)); 8908 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8909 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8910 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8911 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8912 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8913 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8914 PetscCall(PetscFEDestroy(&fe)); 8915 PetscCall(DMCreateDS(rdm)); 8916 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8917 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8918 PetscCall(VecGetArray(*ranks, &r)); 8919 for (c = cStart; c < cEnd; ++c) { 8920 PetscScalar *lr; 8921 8922 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8923 if (lr) *lr = rank; 8924 } 8925 PetscCall(VecRestoreArray(*ranks, &r)); 8926 PetscCall(DMDestroy(&rdm)); 8927 PetscFunctionReturn(PETSC_SUCCESS); 8928 } 8929 8930 /*@ 8931 DMPlexCreateLabelField - Create a field whose value is the label value for that point 8932 8933 Input Parameters: 8934 + dm - The `DMPLEX` 8935 - label - The `DMLabel` 8936 8937 Output Parameter: 8938 . val - The label value field 8939 8940 Options Database Key: 8941 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8942 8943 Level: intermediate 8944 8945 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8946 @*/ 8947 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8948 { 8949 DM rdm, plex; 8950 Vec lval; 8951 PetscSection section; 8952 PetscFE fe; 8953 PetscScalar *v; 8954 PetscInt dim, pStart, pEnd, p, cStart; 8955 DMPolytopeType ct; 8956 char name[PETSC_MAX_PATH_LEN]; 8957 const char *lname, *prefix; 8958 8959 PetscFunctionBeginUser; 8960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8961 PetscAssertPointer(label, 2); 8962 PetscAssertPointer(val, 3); 8963 PetscCall(DMClone(dm, &rdm)); 8964 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 8965 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 8966 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 8967 PetscCall(DMDestroy(&plex)); 8968 PetscCall(DMGetDimension(rdm, &dim)); 8969 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 8970 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 8971 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 8972 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 8973 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 8974 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8975 PetscCall(PetscFEDestroy(&fe)); 8976 PetscCall(DMCreateDS(rdm)); 8977 PetscCall(DMCreateGlobalVector(rdm, val)); 8978 PetscCall(DMCreateLocalVector(rdm, &lval)); 8979 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 8980 PetscCall(DMGetLocalSection(rdm, §ion)); 8981 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 8982 PetscCall(VecGetArray(lval, &v)); 8983 for (p = pStart; p < pEnd; ++p) { 8984 PetscInt cval, dof, off; 8985 8986 PetscCall(PetscSectionGetDof(section, p, &dof)); 8987 if (!dof) continue; 8988 PetscCall(DMLabelGetValue(label, p, &cval)); 8989 PetscCall(PetscSectionGetOffset(section, p, &off)); 8990 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 8991 } 8992 PetscCall(VecRestoreArray(lval, &v)); 8993 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 8994 PetscCall(VecDestroy(&lval)); 8995 PetscCall(DMDestroy(&rdm)); 8996 PetscFunctionReturn(PETSC_SUCCESS); 8997 } 8998 8999 /*@ 9000 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9001 9002 Input Parameter: 9003 . dm - The `DMPLEX` object 9004 9005 Level: developer 9006 9007 Notes: 9008 This is a useful diagnostic when creating meshes programmatically. 9009 9010 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9011 9012 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9013 @*/ 9014 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9015 { 9016 PetscSection coneSection, supportSection; 9017 const PetscInt *cone, *support; 9018 PetscInt coneSize, c, supportSize, s; 9019 PetscInt pStart, pEnd, p, pp, csize, ssize; 9020 PetscBool storagecheck = PETSC_TRUE; 9021 9022 PetscFunctionBegin; 9023 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9024 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9025 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9026 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9027 /* Check that point p is found in the support of its cone points, and vice versa */ 9028 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9029 for (p = pStart; p < pEnd; ++p) { 9030 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9031 PetscCall(DMPlexGetCone(dm, p, &cone)); 9032 for (c = 0; c < coneSize; ++c) { 9033 PetscBool dup = PETSC_FALSE; 9034 PetscInt d; 9035 for (d = c - 1; d >= 0; --d) { 9036 if (cone[c] == cone[d]) { 9037 dup = PETSC_TRUE; 9038 break; 9039 } 9040 } 9041 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9042 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9043 for (s = 0; s < supportSize; ++s) { 9044 if (support[s] == p) break; 9045 } 9046 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9047 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9048 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9049 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9050 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9051 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9052 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9053 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]); 9054 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9055 } 9056 } 9057 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9058 if (p != pp) { 9059 storagecheck = PETSC_FALSE; 9060 continue; 9061 } 9062 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9063 PetscCall(DMPlexGetSupport(dm, p, &support)); 9064 for (s = 0; s < supportSize; ++s) { 9065 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9066 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9067 for (c = 0; c < coneSize; ++c) { 9068 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9069 if (cone[c] != pp) { 9070 c = 0; 9071 break; 9072 } 9073 if (cone[c] == p) break; 9074 } 9075 if (c >= coneSize) { 9076 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9077 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9078 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9079 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9080 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9081 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9082 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9083 } 9084 } 9085 } 9086 if (storagecheck) { 9087 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9088 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9089 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9090 } 9091 PetscFunctionReturn(PETSC_SUCCESS); 9092 } 9093 9094 /* 9095 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. 9096 */ 9097 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9098 { 9099 DMPolytopeType cct; 9100 PetscInt ptpoints[4]; 9101 const PetscInt *cone, *ccone, *ptcone; 9102 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9103 9104 PetscFunctionBegin; 9105 *unsplit = 0; 9106 switch (ct) { 9107 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9108 ptpoints[npt++] = c; 9109 break; 9110 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9111 PetscCall(DMPlexGetCone(dm, c, &cone)); 9112 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9113 for (cp = 0; cp < coneSize; ++cp) { 9114 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9115 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9116 } 9117 break; 9118 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9119 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9120 PetscCall(DMPlexGetCone(dm, c, &cone)); 9121 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9122 for (cp = 0; cp < coneSize; ++cp) { 9123 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9124 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9125 for (ccp = 0; ccp < cconeSize; ++ccp) { 9126 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9127 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9128 PetscInt p; 9129 for (p = 0; p < npt; ++p) 9130 if (ptpoints[p] == ccone[ccp]) break; 9131 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9132 } 9133 } 9134 } 9135 break; 9136 default: 9137 break; 9138 } 9139 for (pt = 0; pt < npt; ++pt) { 9140 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9141 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9142 } 9143 PetscFunctionReturn(PETSC_SUCCESS); 9144 } 9145 9146 /*@ 9147 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9148 9149 Input Parameters: 9150 + dm - The `DMPLEX` object 9151 - cellHeight - Normally 0 9152 9153 Level: developer 9154 9155 Notes: 9156 This is a useful diagnostic when creating meshes programmatically. 9157 Currently applicable only to homogeneous simplex or tensor meshes. 9158 9159 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9160 9161 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9162 @*/ 9163 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9164 { 9165 DMPlexInterpolatedFlag interp; 9166 DMPolytopeType ct; 9167 PetscInt vStart, vEnd, cStart, cEnd, c; 9168 9169 PetscFunctionBegin; 9170 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9171 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9172 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9173 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9174 for (c = cStart; c < cEnd; ++c) { 9175 PetscInt *closure = NULL; 9176 PetscInt coneSize, closureSize, cl, Nv = 0; 9177 9178 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9179 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9180 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9181 if (interp == DMPLEX_INTERPOLATED_FULL) { 9182 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9183 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)); 9184 } 9185 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9186 for (cl = 0; cl < closureSize * 2; cl += 2) { 9187 const PetscInt p = closure[cl]; 9188 if ((p >= vStart) && (p < vEnd)) ++Nv; 9189 } 9190 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9191 /* Special Case: Tensor faces with identified vertices */ 9192 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9193 PetscInt unsplit; 9194 9195 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9196 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9197 } 9198 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)); 9199 } 9200 PetscFunctionReturn(PETSC_SUCCESS); 9201 } 9202 9203 /*@ 9204 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9205 9206 Collective 9207 9208 Input Parameters: 9209 + dm - The `DMPLEX` object 9210 - cellHeight - Normally 0 9211 9212 Level: developer 9213 9214 Notes: 9215 This is a useful diagnostic when creating meshes programmatically. 9216 This routine is only relevant for meshes that are fully interpolated across all ranks. 9217 It will error out if a partially interpolated mesh is given on some rank. 9218 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9219 9220 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9221 9222 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9223 @*/ 9224 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9225 { 9226 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9227 DMPlexInterpolatedFlag interpEnum; 9228 9229 PetscFunctionBegin; 9230 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9231 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9232 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9233 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9234 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9235 PetscFunctionReturn(PETSC_SUCCESS); 9236 } 9237 9238 PetscCall(DMGetDimension(dm, &dim)); 9239 PetscCall(DMPlexGetDepth(dm, &depth)); 9240 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9241 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9242 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9243 for (c = cStart; c < cEnd; ++c) { 9244 const PetscInt *cone, *ornt, *faceSizes, *faces; 9245 const DMPolytopeType *faceTypes; 9246 DMPolytopeType ct; 9247 PetscInt numFaces, coneSize, f; 9248 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9249 9250 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9251 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9252 if (unsplit) continue; 9253 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9254 PetscCall(DMPlexGetCone(dm, c, &cone)); 9255 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9256 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9257 for (cl = 0; cl < closureSize * 2; cl += 2) { 9258 const PetscInt p = closure[cl]; 9259 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9260 } 9261 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9262 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); 9263 for (f = 0; f < numFaces; ++f) { 9264 DMPolytopeType fct; 9265 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9266 9267 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9268 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9269 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9270 const PetscInt p = fclosure[cl]; 9271 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9272 } 9273 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]); 9274 for (v = 0; v < fnumCorners; ++v) { 9275 if (fclosure[v] != faces[fOff + v]) { 9276 PetscInt v1; 9277 9278 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9279 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9280 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9281 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9282 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9283 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]); 9284 } 9285 } 9286 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9287 fOff += faceSizes[f]; 9288 } 9289 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9290 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9291 } 9292 } 9293 PetscFunctionReturn(PETSC_SUCCESS); 9294 } 9295 9296 /*@ 9297 DMPlexCheckGeometry - Check the geometry of mesh cells 9298 9299 Input Parameter: 9300 . dm - The `DMPLEX` object 9301 9302 Level: developer 9303 9304 Notes: 9305 This is a useful diagnostic when creating meshes programmatically. 9306 9307 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9308 9309 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9310 @*/ 9311 PetscErrorCode DMPlexCheckGeometry(DM dm) 9312 { 9313 Vec coordinates; 9314 PetscReal detJ, J[9], refVol = 1.0; 9315 PetscReal vol; 9316 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9317 9318 PetscFunctionBegin; 9319 PetscCall(DMGetDimension(dm, &dim)); 9320 PetscCall(DMGetCoordinateDim(dm, &dE)); 9321 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9322 PetscCall(DMPlexGetDepth(dm, &depth)); 9323 for (d = 0; d < dim; ++d) refVol *= 2.0; 9324 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9325 /* Make sure local coordinates are created, because that step is collective */ 9326 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9327 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9328 for (c = cStart; c < cEnd; ++c) { 9329 DMPolytopeType ct; 9330 PetscInt unsplit; 9331 PetscBool ignoreZeroVol = PETSC_FALSE; 9332 9333 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9334 switch (ct) { 9335 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9336 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9337 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9338 ignoreZeroVol = PETSC_TRUE; 9339 break; 9340 default: 9341 break; 9342 } 9343 switch (ct) { 9344 case DM_POLYTOPE_TRI_PRISM: 9345 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9346 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9347 case DM_POLYTOPE_PYRAMID: 9348 continue; 9349 default: 9350 break; 9351 } 9352 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9353 if (unsplit) continue; 9354 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9355 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); 9356 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9357 /* This should work with periodicity since DG coordinates should be used */ 9358 if (depth > 1) { 9359 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9360 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); 9361 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9362 } 9363 } 9364 PetscFunctionReturn(PETSC_SUCCESS); 9365 } 9366 9367 /*@ 9368 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9369 9370 Collective 9371 9372 Input Parameters: 9373 + dm - The `DMPLEX` object 9374 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9375 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9376 9377 Level: developer 9378 9379 Notes: 9380 This is mainly intended for debugging/testing purposes. 9381 9382 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9383 9384 Extra roots can come from periodic cuts, where additional points appear on the boundary 9385 9386 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9387 @*/ 9388 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9389 { 9390 PetscInt l, nleaves, nroots, overlap; 9391 const PetscInt *locals; 9392 const PetscSFNode *remotes; 9393 PetscBool distributed; 9394 MPI_Comm comm; 9395 PetscMPIInt rank; 9396 9397 PetscFunctionBegin; 9398 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9399 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9400 else pointSF = dm->sf; 9401 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9402 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9403 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9404 { 9405 PetscMPIInt mpiFlag; 9406 9407 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9408 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9409 } 9410 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9411 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9412 if (!distributed) { 9413 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); 9414 PetscFunctionReturn(PETSC_SUCCESS); 9415 } 9416 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); 9417 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9418 9419 /* Check SF graph is compatible with DMPlex chart */ 9420 { 9421 PetscInt pStart, pEnd, maxLeaf; 9422 9423 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9424 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9425 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9426 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9427 } 9428 9429 /* Check Point SF has no local points referenced */ 9430 for (l = 0; l < nleaves; l++) { 9431 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); 9432 } 9433 9434 /* Check there are no cells in interface */ 9435 if (!overlap) { 9436 PetscInt cellHeight, cStart, cEnd; 9437 9438 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9439 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9440 for (l = 0; l < nleaves; ++l) { 9441 const PetscInt point = locals ? locals[l] : l; 9442 9443 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9444 } 9445 } 9446 9447 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9448 { 9449 const PetscInt *rootdegree; 9450 9451 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9452 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9453 for (l = 0; l < nleaves; ++l) { 9454 const PetscInt point = locals ? locals[l] : l; 9455 const PetscInt *cone; 9456 PetscInt coneSize, c, idx; 9457 9458 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9459 PetscCall(DMPlexGetCone(dm, point, &cone)); 9460 for (c = 0; c < coneSize; ++c) { 9461 if (!rootdegree[cone[c]]) { 9462 if (locals) { 9463 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9464 } else { 9465 idx = (cone[c] < nleaves) ? cone[c] : -1; 9466 } 9467 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9468 } 9469 } 9470 } 9471 } 9472 PetscFunctionReturn(PETSC_SUCCESS); 9473 } 9474 9475 /*@ 9476 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9477 9478 Input Parameter: 9479 . dm - The `DMPLEX` object 9480 9481 Level: developer 9482 9483 Notes: 9484 This is a useful diagnostic when creating meshes programmatically. 9485 9486 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9487 9488 Currently does not include `DMPlexCheckCellShape()`. 9489 9490 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9491 @*/ 9492 PetscErrorCode DMPlexCheck(DM dm) 9493 { 9494 PetscInt cellHeight; 9495 9496 PetscFunctionBegin; 9497 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9498 PetscCall(DMPlexCheckSymmetry(dm)); 9499 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9500 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9501 PetscCall(DMPlexCheckGeometry(dm)); 9502 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9503 PetscCall(DMPlexCheckInterfaceCones(dm)); 9504 PetscFunctionReturn(PETSC_SUCCESS); 9505 } 9506 9507 typedef struct cell_stats { 9508 PetscReal min, max, sum, squaresum; 9509 PetscInt count; 9510 } cell_stats_t; 9511 9512 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9513 { 9514 PetscInt i, N = *len; 9515 9516 for (i = 0; i < N; i++) { 9517 cell_stats_t *A = (cell_stats_t *)a; 9518 cell_stats_t *B = (cell_stats_t *)b; 9519 9520 B->min = PetscMin(A->min, B->min); 9521 B->max = PetscMax(A->max, B->max); 9522 B->sum += A->sum; 9523 B->squaresum += A->squaresum; 9524 B->count += A->count; 9525 } 9526 } 9527 9528 /*@ 9529 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9530 9531 Collective 9532 9533 Input Parameters: 9534 + dm - The `DMPLEX` object 9535 . output - If true, statistics will be displayed on `stdout` 9536 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9537 9538 Level: developer 9539 9540 Notes: 9541 This is mainly intended for debugging/testing purposes. 9542 9543 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9544 9545 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9546 @*/ 9547 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9548 { 9549 DM dmCoarse; 9550 cell_stats_t stats, globalStats; 9551 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9552 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9553 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9554 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9555 PetscMPIInt rank, size; 9556 9557 PetscFunctionBegin; 9558 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9559 stats.min = PETSC_MAX_REAL; 9560 stats.max = PETSC_MIN_REAL; 9561 stats.sum = stats.squaresum = 0.; 9562 stats.count = 0; 9563 9564 PetscCallMPI(MPI_Comm_size(comm, &size)); 9565 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9566 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9567 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9568 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9569 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9570 for (c = cStart; c < cEnd; c++) { 9571 PetscInt i; 9572 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9573 9574 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9575 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9576 for (i = 0; i < PetscSqr(cdim); ++i) { 9577 frobJ += J[i] * J[i]; 9578 frobInvJ += invJ[i] * invJ[i]; 9579 } 9580 cond2 = frobJ * frobInvJ; 9581 cond = PetscSqrtReal(cond2); 9582 9583 stats.min = PetscMin(stats.min, cond); 9584 stats.max = PetscMax(stats.max, cond); 9585 stats.sum += cond; 9586 stats.squaresum += cond2; 9587 stats.count++; 9588 if (output && cond > limit) { 9589 PetscSection coordSection; 9590 Vec coordsLocal; 9591 PetscScalar *coords = NULL; 9592 PetscInt Nv, d, clSize, cl, *closure = NULL; 9593 9594 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9595 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9596 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9597 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9598 for (i = 0; i < Nv / cdim; ++i) { 9599 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9600 for (d = 0; d < cdim; ++d) { 9601 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9602 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9603 } 9604 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9605 } 9606 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9607 for (cl = 0; cl < clSize * 2; cl += 2) { 9608 const PetscInt edge = closure[cl]; 9609 9610 if ((edge >= eStart) && (edge < eEnd)) { 9611 PetscReal len; 9612 9613 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9614 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9615 } 9616 } 9617 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9618 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9619 } 9620 } 9621 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9622 9623 if (size > 1) { 9624 PetscMPIInt blockLengths[2] = {4, 1}; 9625 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9626 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9627 MPI_Op statReduce; 9628 9629 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9630 PetscCallMPI(MPI_Type_commit(&statType)); 9631 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9632 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9633 PetscCallMPI(MPI_Op_free(&statReduce)); 9634 PetscCallMPI(MPI_Type_free(&statType)); 9635 } else { 9636 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9637 } 9638 if (rank == 0) { 9639 count = globalStats.count; 9640 min = globalStats.min; 9641 max = globalStats.max; 9642 mean = globalStats.sum / globalStats.count; 9643 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9644 } 9645 9646 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)); 9647 PetscCall(PetscFree2(J, invJ)); 9648 9649 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9650 if (dmCoarse) { 9651 PetscBool isplex; 9652 9653 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9654 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9655 } 9656 PetscFunctionReturn(PETSC_SUCCESS); 9657 } 9658 9659 /*@ 9660 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9661 orthogonal quality below given tolerance. 9662 9663 Collective 9664 9665 Input Parameters: 9666 + dm - The `DMPLEX` object 9667 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9668 - atol - [0, 1] Absolute tolerance for tagging cells. 9669 9670 Output Parameters: 9671 + OrthQual - `Vec` containing orthogonal quality per cell 9672 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9673 9674 Options Database Keys: 9675 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9676 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9677 9678 Level: intermediate 9679 9680 Notes: 9681 Orthogonal quality is given by the following formula\: 9682 9683 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9684 9685 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 9686 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9687 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9688 calculating the cosine of the angle between these vectors. 9689 9690 Orthogonal quality ranges from 1 (best) to 0 (worst). 9691 9692 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9693 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9694 9695 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9696 9697 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9698 @*/ 9699 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9700 { 9701 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9702 PetscInt *idx; 9703 PetscScalar *oqVals; 9704 const PetscScalar *cellGeomArr, *faceGeomArr; 9705 PetscReal *ci, *fi, *Ai; 9706 MPI_Comm comm; 9707 Vec cellgeom, facegeom; 9708 DM dmFace, dmCell; 9709 IS glob; 9710 ISLocalToGlobalMapping ltog; 9711 PetscViewer vwr; 9712 9713 PetscFunctionBegin; 9714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9715 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9716 PetscAssertPointer(OrthQual, 4); 9717 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9718 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9719 PetscCall(DMGetDimension(dm, &nc)); 9720 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9721 { 9722 DMPlexInterpolatedFlag interpFlag; 9723 9724 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9725 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9726 PetscMPIInt rank; 9727 9728 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9729 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9730 } 9731 } 9732 if (OrthQualLabel) { 9733 PetscAssertPointer(OrthQualLabel, 5); 9734 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9735 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9736 } else { 9737 *OrthQualLabel = NULL; 9738 } 9739 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9740 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9741 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9742 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9743 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9744 PetscCall(VecCreate(comm, OrthQual)); 9745 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9746 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9747 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9748 PetscCall(VecSetUp(*OrthQual)); 9749 PetscCall(ISDestroy(&glob)); 9750 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9751 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9752 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9753 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9754 PetscCall(VecGetDM(cellgeom, &dmCell)); 9755 PetscCall(VecGetDM(facegeom, &dmFace)); 9756 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9757 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9758 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9759 PetscInt cellarr[2], *adj = NULL; 9760 PetscScalar *cArr, *fArr; 9761 PetscReal minvalc = 1.0, minvalf = 1.0; 9762 PetscFVCellGeom *cg; 9763 9764 idx[cellIter] = cell - cStart; 9765 cellarr[0] = cell; 9766 /* Make indexing into cellGeom easier */ 9767 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9768 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9769 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9770 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9771 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9772 PetscInt i; 9773 const PetscInt neigh = adj[cellneigh]; 9774 PetscReal normci = 0, normfi = 0, normai = 0; 9775 PetscFVCellGeom *cgneigh; 9776 PetscFVFaceGeom *fg; 9777 9778 /* Don't count ourselves in the neighbor list */ 9779 if (neigh == cell) continue; 9780 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9781 cellarr[1] = neigh; 9782 { 9783 PetscInt numcovpts; 9784 const PetscInt *covpts; 9785 9786 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9787 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9788 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9789 } 9790 9791 /* Compute c_i, f_i and their norms */ 9792 for (i = 0; i < nc; i++) { 9793 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9794 fi[i] = fg->centroid[i] - cg->centroid[i]; 9795 Ai[i] = fg->normal[i]; 9796 normci += PetscPowReal(ci[i], 2); 9797 normfi += PetscPowReal(fi[i], 2); 9798 normai += PetscPowReal(Ai[i], 2); 9799 } 9800 normci = PetscSqrtReal(normci); 9801 normfi = PetscSqrtReal(normfi); 9802 normai = PetscSqrtReal(normai); 9803 9804 /* Normalize and compute for each face-cell-normal pair */ 9805 for (i = 0; i < nc; i++) { 9806 ci[i] = ci[i] / normci; 9807 fi[i] = fi[i] / normfi; 9808 Ai[i] = Ai[i] / normai; 9809 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9810 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9811 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9812 } 9813 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9814 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9815 } 9816 PetscCall(PetscFree(adj)); 9817 PetscCall(PetscFree2(cArr, fArr)); 9818 /* Defer to cell if they're equal */ 9819 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9820 if (OrthQualLabel) { 9821 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9822 } 9823 } 9824 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9825 PetscCall(VecAssemblyBegin(*OrthQual)); 9826 PetscCall(VecAssemblyEnd(*OrthQual)); 9827 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9828 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9829 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9830 if (OrthQualLabel) { 9831 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9832 } 9833 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9834 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9835 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9836 PetscFunctionReturn(PETSC_SUCCESS); 9837 } 9838 9839 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9840 * interpolator construction */ 9841 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9842 { 9843 PetscSection section, newSection, gsection; 9844 PetscSF sf; 9845 PetscBool hasConstraints, ghasConstraints; 9846 9847 PetscFunctionBegin; 9848 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9849 PetscAssertPointer(odm, 2); 9850 PetscCall(DMGetLocalSection(dm, §ion)); 9851 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9852 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9853 if (!ghasConstraints) { 9854 PetscCall(PetscObjectReference((PetscObject)dm)); 9855 *odm = dm; 9856 PetscFunctionReturn(PETSC_SUCCESS); 9857 } 9858 PetscCall(DMClone(dm, odm)); 9859 PetscCall(DMCopyFields(dm, *odm)); 9860 PetscCall(DMGetLocalSection(*odm, &newSection)); 9861 PetscCall(DMGetPointSF(*odm, &sf)); 9862 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9863 PetscCall(DMSetGlobalSection(*odm, gsection)); 9864 PetscCall(PetscSectionDestroy(&gsection)); 9865 PetscFunctionReturn(PETSC_SUCCESS); 9866 } 9867 9868 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9869 { 9870 DM dmco, dmfo; 9871 Mat interpo; 9872 Vec rscale; 9873 Vec cglobalo, clocal; 9874 Vec fglobal, fglobalo, flocal; 9875 PetscBool regular; 9876 9877 PetscFunctionBegin; 9878 PetscCall(DMGetFullDM(dmc, &dmco)); 9879 PetscCall(DMGetFullDM(dmf, &dmfo)); 9880 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9881 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9882 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9883 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9884 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9885 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9886 PetscCall(VecSet(cglobalo, 0.)); 9887 PetscCall(VecSet(clocal, 0.)); 9888 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9889 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9890 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9891 PetscCall(VecSet(fglobal, 0.)); 9892 PetscCall(VecSet(fglobalo, 0.)); 9893 PetscCall(VecSet(flocal, 0.)); 9894 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9895 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9896 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9897 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9898 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9899 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9900 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9901 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9902 *shift = fglobal; 9903 PetscCall(VecDestroy(&flocal)); 9904 PetscCall(VecDestroy(&fglobalo)); 9905 PetscCall(VecDestroy(&clocal)); 9906 PetscCall(VecDestroy(&cglobalo)); 9907 PetscCall(VecDestroy(&rscale)); 9908 PetscCall(MatDestroy(&interpo)); 9909 PetscCall(DMDestroy(&dmfo)); 9910 PetscCall(DMDestroy(&dmco)); 9911 PetscFunctionReturn(PETSC_SUCCESS); 9912 } 9913 9914 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9915 { 9916 PetscObject shifto; 9917 Vec shift; 9918 9919 PetscFunctionBegin; 9920 if (!interp) { 9921 Vec rscale; 9922 9923 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9924 PetscCall(VecDestroy(&rscale)); 9925 } else { 9926 PetscCall(PetscObjectReference((PetscObject)interp)); 9927 } 9928 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9929 if (!shifto) { 9930 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9931 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9932 shifto = (PetscObject)shift; 9933 PetscCall(VecDestroy(&shift)); 9934 } 9935 shift = (Vec)shifto; 9936 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9937 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9938 PetscCall(MatDestroy(&interp)); 9939 PetscFunctionReturn(PETSC_SUCCESS); 9940 } 9941 9942 /* Pointwise interpolation 9943 Just code FEM for now 9944 u^f = I u^c 9945 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9946 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9947 I_{ij} = psi^f_i phi^c_j 9948 */ 9949 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9950 { 9951 PetscSection gsc, gsf; 9952 PetscInt m, n; 9953 void *ctx; 9954 DM cdm; 9955 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9956 9957 PetscFunctionBegin; 9958 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9959 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9960 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9961 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9962 9963 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9964 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9965 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9966 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9967 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9968 9969 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9970 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9971 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9972 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9973 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9974 if (scaling) { 9975 /* Use naive scaling */ 9976 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9977 } 9978 PetscFunctionReturn(PETSC_SUCCESS); 9979 } 9980 9981 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9982 { 9983 VecScatter ctx; 9984 9985 PetscFunctionBegin; 9986 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9987 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9988 PetscCall(VecScatterDestroy(&ctx)); 9989 PetscFunctionReturn(PETSC_SUCCESS); 9990 } 9991 9992 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[]) 9993 { 9994 const PetscInt Nc = uOff[1] - uOff[0]; 9995 PetscInt c; 9996 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9997 } 9998 9999 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 10000 { 10001 DM dmc; 10002 PetscDS ds; 10003 Vec ones, locmass; 10004 IS cellIS; 10005 PetscFormKey key; 10006 PetscInt depth; 10007 10008 PetscFunctionBegin; 10009 PetscCall(DMClone(dm, &dmc)); 10010 PetscCall(DMCopyDisc(dm, dmc)); 10011 PetscCall(DMGetDS(dmc, &ds)); 10012 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10013 PetscCall(DMCreateGlobalVector(dmc, mass)); 10014 PetscCall(DMGetLocalVector(dmc, &ones)); 10015 PetscCall(DMGetLocalVector(dmc, &locmass)); 10016 PetscCall(DMPlexGetDepth(dmc, &depth)); 10017 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10018 PetscCall(VecSet(locmass, 0.0)); 10019 PetscCall(VecSet(ones, 1.0)); 10020 key.label = NULL; 10021 key.value = 0; 10022 key.field = 0; 10023 key.part = 0; 10024 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10025 PetscCall(ISDestroy(&cellIS)); 10026 PetscCall(VecSet(*mass, 0.0)); 10027 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 10028 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 10029 PetscCall(DMRestoreLocalVector(dmc, &ones)); 10030 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 10031 PetscCall(DMDestroy(&dmc)); 10032 PetscFunctionReturn(PETSC_SUCCESS); 10033 } 10034 10035 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10036 { 10037 PetscSection gsc, gsf; 10038 PetscInt m, n; 10039 void *ctx; 10040 DM cdm; 10041 PetscBool regular; 10042 10043 PetscFunctionBegin; 10044 if (dmFine == dmCoarse) { 10045 DM dmc; 10046 PetscDS ds; 10047 PetscWeakForm wf; 10048 Vec u; 10049 IS cellIS; 10050 PetscFormKey key; 10051 PetscInt depth; 10052 10053 PetscCall(DMClone(dmFine, &dmc)); 10054 PetscCall(DMCopyDisc(dmFine, dmc)); 10055 PetscCall(DMGetDS(dmc, &ds)); 10056 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10057 PetscCall(PetscWeakFormClear(wf)); 10058 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10059 PetscCall(DMCreateMatrix(dmc, mass)); 10060 PetscCall(DMGetLocalVector(dmc, &u)); 10061 PetscCall(DMPlexGetDepth(dmc, &depth)); 10062 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10063 PetscCall(MatZeroEntries(*mass)); 10064 key.label = NULL; 10065 key.value = 0; 10066 key.field = 0; 10067 key.part = 0; 10068 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10069 PetscCall(ISDestroy(&cellIS)); 10070 PetscCall(DMRestoreLocalVector(dmc, &u)); 10071 PetscCall(DMDestroy(&dmc)); 10072 } else { 10073 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10074 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10075 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10076 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10077 10078 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10079 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10080 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10081 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10082 10083 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10084 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10085 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10086 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10087 } 10088 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10089 PetscFunctionReturn(PETSC_SUCCESS); 10090 } 10091 10092 /*@ 10093 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10094 10095 Input Parameter: 10096 . dm - The `DMPLEX` object 10097 10098 Output Parameter: 10099 . regular - The flag 10100 10101 Level: intermediate 10102 10103 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10104 @*/ 10105 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10106 { 10107 PetscFunctionBegin; 10108 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10109 PetscAssertPointer(regular, 2); 10110 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10111 PetscFunctionReturn(PETSC_SUCCESS); 10112 } 10113 10114 /*@ 10115 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10116 10117 Input Parameters: 10118 + dm - The `DMPLEX` object 10119 - regular - The flag 10120 10121 Level: intermediate 10122 10123 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10124 @*/ 10125 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10126 { 10127 PetscFunctionBegin; 10128 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10129 ((DM_Plex *)dm->data)->regularRefinement = regular; 10130 PetscFunctionReturn(PETSC_SUCCESS); 10131 } 10132 10133 /*@ 10134 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10135 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10136 10137 Not Collective 10138 10139 Input Parameter: 10140 . dm - The `DMPLEX` object 10141 10142 Output Parameters: 10143 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10144 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10145 10146 Level: intermediate 10147 10148 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10149 @*/ 10150 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10151 { 10152 DM_Plex *plex = (DM_Plex *)dm->data; 10153 10154 PetscFunctionBegin; 10155 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10156 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10157 if (anchorSection) *anchorSection = plex->anchorSection; 10158 if (anchorIS) *anchorIS = plex->anchorIS; 10159 PetscFunctionReturn(PETSC_SUCCESS); 10160 } 10161 10162 /*@ 10163 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10164 10165 Collective 10166 10167 Input Parameters: 10168 + dm - The `DMPLEX` object 10169 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10170 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10171 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10172 10173 Level: intermediate 10174 10175 Notes: 10176 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10177 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10178 combination of other points' degrees of freedom. 10179 10180 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10181 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10182 10183 The reference counts of `anchorSection` and `anchorIS` are incremented. 10184 10185 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10186 @*/ 10187 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10188 { 10189 DM_Plex *plex = (DM_Plex *)dm->data; 10190 PetscMPIInt result; 10191 10192 PetscFunctionBegin; 10193 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10194 if (anchorSection) { 10195 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10196 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10197 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10198 } 10199 if (anchorIS) { 10200 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10201 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10202 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10203 } 10204 10205 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10206 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10207 plex->anchorSection = anchorSection; 10208 10209 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10210 PetscCall(ISDestroy(&plex->anchorIS)); 10211 plex->anchorIS = anchorIS; 10212 10213 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10214 PetscInt size, a, pStart, pEnd; 10215 const PetscInt *anchors; 10216 10217 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10218 PetscCall(ISGetLocalSize(anchorIS, &size)); 10219 PetscCall(ISGetIndices(anchorIS, &anchors)); 10220 for (a = 0; a < size; a++) { 10221 PetscInt p; 10222 10223 p = anchors[a]; 10224 if (p >= pStart && p < pEnd) { 10225 PetscInt dof; 10226 10227 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10228 if (dof) { 10229 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10230 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10231 } 10232 } 10233 } 10234 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10235 } 10236 /* reset the generic constraints */ 10237 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10238 PetscFunctionReturn(PETSC_SUCCESS); 10239 } 10240 10241 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10242 { 10243 PetscSection anchorSection; 10244 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10245 10246 PetscFunctionBegin; 10247 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10248 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10249 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10250 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10251 if (numFields) { 10252 PetscInt f; 10253 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10254 10255 for (f = 0; f < numFields; f++) { 10256 PetscInt numComp; 10257 10258 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10259 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10260 } 10261 } 10262 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10263 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10264 pStart = PetscMax(pStart, sStart); 10265 pEnd = PetscMin(pEnd, sEnd); 10266 pEnd = PetscMax(pStart, pEnd); 10267 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10268 for (p = pStart; p < pEnd; p++) { 10269 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10270 if (dof) { 10271 PetscCall(PetscSectionGetDof(section, p, &dof)); 10272 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10273 for (f = 0; f < numFields; f++) { 10274 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10275 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10276 } 10277 } 10278 } 10279 PetscCall(PetscSectionSetUp(*cSec)); 10280 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10281 PetscFunctionReturn(PETSC_SUCCESS); 10282 } 10283 10284 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10285 { 10286 PetscSection aSec; 10287 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10288 const PetscInt *anchors; 10289 PetscInt numFields, f; 10290 IS aIS; 10291 MatType mtype; 10292 PetscBool iscuda, iskokkos; 10293 10294 PetscFunctionBegin; 10295 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10296 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10297 PetscCall(PetscSectionGetStorageSize(section, &n)); 10298 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10299 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10300 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10301 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10302 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10303 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10304 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10305 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10306 else mtype = MATSEQAIJ; 10307 PetscCall(MatSetType(*cMat, mtype)); 10308 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10309 PetscCall(ISGetIndices(aIS, &anchors)); 10310 /* cSec will be a subset of aSec and section */ 10311 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10312 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10313 PetscCall(PetscMalloc1(m + 1, &i)); 10314 i[0] = 0; 10315 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10316 for (p = pStart; p < pEnd; p++) { 10317 PetscInt rDof, rOff, r; 10318 10319 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10320 if (!rDof) continue; 10321 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10322 if (numFields) { 10323 for (f = 0; f < numFields; f++) { 10324 annz = 0; 10325 for (r = 0; r < rDof; r++) { 10326 a = anchors[rOff + r]; 10327 if (a < sStart || a >= sEnd) continue; 10328 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10329 annz += aDof; 10330 } 10331 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10332 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10333 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10334 } 10335 } else { 10336 annz = 0; 10337 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10338 for (q = 0; q < dof; q++) { 10339 a = anchors[rOff + q]; 10340 if (a < sStart || a >= sEnd) continue; 10341 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10342 annz += aDof; 10343 } 10344 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10345 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10346 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10347 } 10348 } 10349 nnz = i[m]; 10350 PetscCall(PetscMalloc1(nnz, &j)); 10351 offset = 0; 10352 for (p = pStart; p < pEnd; p++) { 10353 if (numFields) { 10354 for (f = 0; f < numFields; f++) { 10355 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10356 for (q = 0; q < dof; q++) { 10357 PetscInt rDof, rOff, r; 10358 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10359 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10360 for (r = 0; r < rDof; r++) { 10361 PetscInt s; 10362 10363 a = anchors[rOff + r]; 10364 if (a < sStart || a >= sEnd) continue; 10365 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10366 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10367 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10368 } 10369 } 10370 } 10371 } else { 10372 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10373 for (q = 0; q < dof; q++) { 10374 PetscInt rDof, rOff, r; 10375 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10376 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10377 for (r = 0; r < rDof; r++) { 10378 PetscInt s; 10379 10380 a = anchors[rOff + r]; 10381 if (a < sStart || a >= sEnd) continue; 10382 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10383 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10384 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10385 } 10386 } 10387 } 10388 } 10389 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10390 PetscCall(PetscFree(i)); 10391 PetscCall(PetscFree(j)); 10392 PetscCall(ISRestoreIndices(aIS, &anchors)); 10393 PetscFunctionReturn(PETSC_SUCCESS); 10394 } 10395 10396 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10397 { 10398 DM_Plex *plex = (DM_Plex *)dm->data; 10399 PetscSection anchorSection, section, cSec; 10400 Mat cMat; 10401 10402 PetscFunctionBegin; 10403 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10404 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10405 if (anchorSection) { 10406 PetscInt Nf; 10407 10408 PetscCall(DMGetLocalSection(dm, §ion)); 10409 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10410 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10411 PetscCall(DMGetNumFields(dm, &Nf)); 10412 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10413 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10414 PetscCall(PetscSectionDestroy(&cSec)); 10415 PetscCall(MatDestroy(&cMat)); 10416 } 10417 PetscFunctionReturn(PETSC_SUCCESS); 10418 } 10419 10420 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10421 { 10422 IS subis; 10423 PetscSection section, subsection; 10424 10425 PetscFunctionBegin; 10426 PetscCall(DMGetLocalSection(dm, §ion)); 10427 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10428 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10429 /* Create subdomain */ 10430 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10431 /* Create submodel */ 10432 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10433 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10434 PetscCall(DMSetLocalSection(*subdm, subsection)); 10435 PetscCall(PetscSectionDestroy(&subsection)); 10436 PetscCall(DMCopyDisc(dm, *subdm)); 10437 /* Create map from submodel to global model */ 10438 if (is) { 10439 PetscSection sectionGlobal, subsectionGlobal; 10440 IS spIS; 10441 const PetscInt *spmap; 10442 PetscInt *subIndices; 10443 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10444 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10445 10446 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10447 PetscCall(ISGetIndices(spIS, &spmap)); 10448 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10449 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10450 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10451 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10452 for (p = pStart; p < pEnd; ++p) { 10453 PetscInt gdof, pSubSize = 0; 10454 10455 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10456 if (gdof > 0) { 10457 for (f = 0; f < Nf; ++f) { 10458 PetscInt fdof, fcdof; 10459 10460 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10461 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10462 pSubSize += fdof - fcdof; 10463 } 10464 subSize += pSubSize; 10465 if (pSubSize) { 10466 if (bs < 0) { 10467 bs = pSubSize; 10468 } else if (bs != pSubSize) { 10469 /* Layout does not admit a pointwise block size */ 10470 bs = 1; 10471 } 10472 } 10473 } 10474 } 10475 /* Must have same blocksize on all procs (some might have no points) */ 10476 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10477 bsLocal[1] = bs; 10478 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10479 if (bsMinMax[0] != bsMinMax[1]) { 10480 bs = 1; 10481 } else { 10482 bs = bsMinMax[0]; 10483 } 10484 PetscCall(PetscMalloc1(subSize, &subIndices)); 10485 for (p = pStart; p < pEnd; ++p) { 10486 PetscInt gdof, goff; 10487 10488 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10489 if (gdof > 0) { 10490 const PetscInt point = spmap[p]; 10491 10492 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10493 for (f = 0; f < Nf; ++f) { 10494 PetscInt fdof, fcdof, fc, f2, poff = 0; 10495 10496 /* Can get rid of this loop by storing field information in the global section */ 10497 for (f2 = 0; f2 < f; ++f2) { 10498 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10499 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10500 poff += fdof - fcdof; 10501 } 10502 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10503 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10504 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10505 } 10506 } 10507 } 10508 PetscCall(ISRestoreIndices(spIS, &spmap)); 10509 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10510 if (bs > 1) { 10511 /* We need to check that the block size does not come from non-contiguous fields */ 10512 PetscInt i, j, set = 1; 10513 for (i = 0; i < subSize; i += bs) { 10514 for (j = 0; j < bs; ++j) { 10515 if (subIndices[i + j] != subIndices[i] + j) { 10516 set = 0; 10517 break; 10518 } 10519 } 10520 } 10521 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10522 } 10523 /* Attach nullspace */ 10524 for (f = 0; f < Nf; ++f) { 10525 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10526 if ((*subdm)->nullspaceConstructors[f]) break; 10527 } 10528 if (f < Nf) { 10529 MatNullSpace nullSpace; 10530 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10531 10532 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10533 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10534 } 10535 } 10536 PetscFunctionReturn(PETSC_SUCCESS); 10537 } 10538 10539 /*@ 10540 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10541 10542 Input Parameters: 10543 + dm - The `DM` 10544 - dummy - unused argument 10545 10546 Options Database Key: 10547 . -dm_plex_monitor_throughput - Activate the monitor 10548 10549 Level: developer 10550 10551 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10552 @*/ 10553 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10554 { 10555 PetscLogHandler default_handler; 10556 10557 PetscFunctionBegin; 10558 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10559 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10560 if (default_handler) { 10561 PetscLogEvent event; 10562 PetscEventPerfInfo eventInfo; 10563 PetscReal cellRate, flopRate; 10564 PetscInt cStart, cEnd, Nf, N; 10565 const char *name; 10566 10567 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10568 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10569 PetscCall(DMGetNumFields(dm, &Nf)); 10570 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10571 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10572 N = (cEnd - cStart) * Nf * eventInfo.count; 10573 flopRate = eventInfo.flops / eventInfo.time; 10574 cellRate = N / eventInfo.time; 10575 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))); 10576 } else { 10577 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."); 10578 } 10579 PetscFunctionReturn(PETSC_SUCCESS); 10580 } 10581