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