1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 15 16 PetscBool Plexcite = PETSC_FALSE; 17 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 18 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 19 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 20 "journal = {SIAM Journal on Scientific Computing},\n" 21 "volume = {38},\n" 22 "number = {5},\n" 23 "pages = {S143--S155},\n" 24 "eprint = {http://arxiv.org/abs/1506.07749},\n" 25 "doi = {10.1137/15M1026092},\n" 26 "year = {2016},\n" 27 "petsc_uses={DMPlex},\n}\n"; 28 29 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 30 31 /*@ 32 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 33 34 Input Parameter: 35 . dm - The `DMPLEX` object 36 37 Output Parameter: 38 . simplex - Flag checking for a simplex 39 40 Level: intermediate 41 42 Note: 43 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 44 If the mesh has no cells, this returns `PETSC_FALSE`. 45 46 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 47 @*/ 48 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 49 { 50 DMPolytopeType ct; 51 PetscInt cStart, cEnd; 52 53 PetscFunctionBegin; 54 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 55 if (cEnd <= cStart) { 56 *simplex = PETSC_FALSE; 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 60 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 64 /*@ 65 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 66 67 Input Parameters: 68 + dm - The `DMPLEX` object 69 - height - The cell height in the Plex, 0 is the default 70 71 Output Parameters: 72 + cStart - The first "normal" cell 73 - cEnd - The upper bound on "normal" cells 74 75 Level: developer 76 77 Note: 78 This function requires that tensor cells are ordered last. 79 80 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 81 @*/ 82 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 83 { 84 DMLabel ctLabel; 85 IS valueIS; 86 const PetscInt *ctypes; 87 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 88 89 PetscFunctionBegin; 90 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 91 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 92 PetscCall(ISGetLocalSize(valueIS, &Nct)); 93 PetscCall(ISGetIndices(valueIS, &ctypes)); 94 if (!Nct) cS = cE = 0; 95 for (PetscInt t = 0; t < Nct; ++t) { 96 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 97 PetscInt ctS, ctE, ht; 98 99 if (ct == DM_POLYTOPE_UNKNOWN) { 100 // If any cells are not typed, just use all cells 101 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 102 break; 103 } 104 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 105 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 106 if (ctS >= ctE) continue; 107 // Check that a point has the right height 108 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 109 if (ht != height) continue; 110 cS = PetscMin(cS, ctS); 111 cE = PetscMax(cE, ctE); 112 } 113 PetscCall(ISDestroy(&valueIS)); 114 // Reset label for fast lookup 115 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 116 if (cStart) *cStart = cS; 117 if (cEnd) *cEnd = cE; 118 PetscFunctionReturn(PETSC_SUCCESS); 119 } 120 121 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 122 { 123 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 124 PetscInt *sStart, *sEnd; 125 PetscViewerVTKFieldType *ft; 126 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 127 DMLabel depthLabel, ctLabel; 128 129 PetscFunctionBegin; 130 131 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 132 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 133 PetscCall(DMGetCoordinateDim(dm, &cdim)); 134 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 135 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 136 if (field >= 0) { 137 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 138 } else { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 140 } 141 142 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 143 PetscCall(DMPlexGetDepth(dm, &depth)); 144 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 145 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 146 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 147 const DMPolytopeType ict = (DMPolytopeType)c; 148 PetscInt dep; 149 150 if (ict == DM_POLYTOPE_FV_GHOST) continue; 151 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 152 if (pStart >= 0) { 153 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 154 if (dep != depth - cellHeight) continue; 155 } 156 if (field >= 0) { 157 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 158 } else { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 160 } 161 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 162 } 163 164 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 165 *types = 0; 166 167 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 168 if (globalvcdof[c]) ++(*types); 169 } 170 171 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 172 t = 0; 173 if (globalvcdof[DM_NUM_POLYTOPES]) { 174 sStart[t] = vStart; 175 sEnd[t] = vEnd; 176 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 177 ++t; 178 } 179 180 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 181 if (globalvcdof[c]) { 182 const DMPolytopeType ict = (DMPolytopeType)c; 183 184 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 185 sStart[t] = cStart; 186 sEnd[t] = cEnd; 187 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 188 ++t; 189 } 190 } 191 192 if (!(*types)) { 193 if (field >= 0) { 194 const char *fieldname; 195 196 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 197 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 198 } else { 199 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 200 } 201 } 202 203 *ssStart = sStart; 204 *ssEnd = sEnd; 205 *sft = ft; 206 PetscFunctionReturn(PETSC_SUCCESS); 207 } 208 209 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 210 { 211 PetscFunctionBegin; 212 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 213 PetscFunctionReturn(PETSC_SUCCESS); 214 } 215 216 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 217 { 218 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 219 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 220 221 PetscFunctionBegin; 222 *ft = PETSC_VTK_INVALID; 223 PetscCall(DMGetCoordinateDim(dm, &cdim)); 224 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 225 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 226 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 227 if (field >= 0) { 228 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 229 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 230 } else { 231 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 232 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 233 } 234 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 235 if (globalvcdof[0]) { 236 *sStart = vStart; 237 *sEnd = vEnd; 238 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 239 else *ft = PETSC_VTK_POINT_FIELD; 240 } else if (globalvcdof[1]) { 241 *sStart = cStart; 242 *sEnd = cEnd; 243 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 244 else *ft = PETSC_VTK_CELL_FIELD; 245 } else { 246 if (field >= 0) { 247 const char *fieldname; 248 249 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 250 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 251 } else { 252 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 253 } 254 } 255 PetscFunctionReturn(PETSC_SUCCESS); 256 } 257 258 /*@ 259 DMPlexVecView1D - Plot many 1D solutions on the same line graph 260 261 Collective 262 263 Input Parameters: 264 + dm - The `DMPLEX` object 265 . n - The number of vectors 266 . u - The array of local vectors 267 - viewer - The `PetscViewer` 268 269 Level: advanced 270 271 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 272 @*/ 273 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 274 { 275 PetscDS ds; 276 PetscDraw draw = NULL; 277 PetscDrawLG lg; 278 Vec coordinates; 279 const PetscScalar *coords, **sol; 280 PetscReal *vals; 281 PetscInt *Nc; 282 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 283 char **names; 284 285 PetscFunctionBegin; 286 PetscCall(DMGetDS(dm, &ds)); 287 PetscCall(PetscDSGetNumFields(ds, &Nf)); 288 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 289 PetscCall(PetscDSGetComponents(ds, &Nc)); 290 291 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 292 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 293 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 294 295 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 296 for (i = 0, l = 0; i < n; ++i) { 297 const char *vname; 298 299 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 300 for (f = 0; f < Nf; ++f) { 301 PetscObject disc; 302 const char *fname; 303 char tmpname[PETSC_MAX_PATH_LEN]; 304 305 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 306 /* TODO Create names for components */ 307 for (c = 0; c < Nc[f]; ++c, ++l) { 308 PetscCall(PetscObjectGetName(disc, &fname)); 309 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 310 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 311 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 312 PetscCall(PetscStrallocpy(tmpname, &names[l])); 313 } 314 } 315 } 316 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 317 /* Just add P_1 support for now */ 318 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 319 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 320 PetscCall(VecGetArrayRead(coordinates, &coords)); 321 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 322 for (v = vStart; v < vEnd; ++v) { 323 PetscScalar *x, *svals; 324 325 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 326 for (i = 0; i < n; ++i) { 327 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 328 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 329 } 330 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 331 } 332 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 333 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 334 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 335 PetscCall(PetscFree3(sol, names, vals)); 336 337 PetscCall(PetscDrawLGDraw(lg)); 338 PetscCall(PetscDrawLGDestroy(&lg)); 339 PetscFunctionReturn(PETSC_SUCCESS); 340 } 341 342 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 343 { 344 DM dm; 345 346 PetscFunctionBegin; 347 PetscCall(VecGetDM(u, &dm)); 348 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 349 PetscFunctionReturn(PETSC_SUCCESS); 350 } 351 352 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 353 { 354 DM dm; 355 PetscSection s; 356 PetscDraw draw, popup; 357 DM cdm; 358 PetscSection coordSection; 359 Vec coordinates; 360 const PetscScalar *array; 361 PetscReal lbound[3], ubound[3]; 362 PetscReal vbound[2], time; 363 PetscBool flg; 364 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 365 const char *name; 366 char title[PETSC_MAX_PATH_LEN]; 367 368 PetscFunctionBegin; 369 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 370 PetscCall(VecGetDM(v, &dm)); 371 PetscCall(DMGetCoordinateDim(dm, &dim)); 372 PetscCall(DMGetLocalSection(dm, &s)); 373 PetscCall(PetscSectionGetNumFields(s, &Nf)); 374 PetscCall(DMGetCoarsenLevel(dm, &level)); 375 PetscCall(DMGetCoordinateDM(dm, &cdm)); 376 PetscCall(DMGetLocalSection(cdm, &coordSection)); 377 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 378 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 379 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 380 381 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 382 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 383 384 PetscCall(VecGetLocalSize(coordinates, &N)); 385 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 386 PetscCall(PetscDrawClear(draw)); 387 388 /* Could implement something like DMDASelectFields() */ 389 for (f = 0; f < Nf; ++f) { 390 DM fdm = dm; 391 Vec fv = v; 392 IS fis; 393 char prefix[PETSC_MAX_PATH_LEN]; 394 const char *fname; 395 396 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 397 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 398 399 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 400 else prefix[0] = '\0'; 401 if (Nf > 1) { 402 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 403 PetscCall(VecGetSubVector(v, fis, &fv)); 404 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 405 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 406 } 407 for (comp = 0; comp < Nc; ++comp, ++w) { 408 PetscInt nmax = 2; 409 410 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 411 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 412 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 413 PetscCall(PetscDrawSetTitle(draw, title)); 414 415 /* TODO Get max and min only for this component */ 416 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 417 if (!flg) { 418 PetscCall(VecMin(fv, NULL, &vbound[0])); 419 PetscCall(VecMax(fv, NULL, &vbound[1])); 420 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 421 } 422 423 PetscCall(PetscDrawGetPopup(draw, &popup)); 424 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 425 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 426 PetscCall(VecGetArrayRead(fv, &array)); 427 for (c = cStart; c < cEnd; ++c) { 428 PetscScalar *coords = NULL, *a = NULL; 429 const PetscScalar *coords_arr; 430 PetscBool isDG; 431 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 432 433 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 434 if (a) { 435 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 436 color[1] = color[2] = color[3] = color[0]; 437 } else { 438 PetscScalar *vals = NULL; 439 PetscInt numVals, va; 440 441 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 442 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); 443 switch (numVals / Nc) { 444 case 3: /* P1 Triangle */ 445 case 4: /* P1 Quadrangle */ 446 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 447 break; 448 case 6: /* P2 Triangle */ 449 case 8: /* P2 Quadrangle */ 450 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 451 break; 452 default: 453 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 454 } 455 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 456 } 457 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 458 switch (numCoords) { 459 case 6: 460 case 12: /* Localized triangle */ 461 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])); 462 break; 463 case 8: 464 case 16: /* Localized quadrilateral */ 465 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])); 466 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])); 467 break; 468 default: 469 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 470 } 471 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 472 } 473 PetscCall(VecRestoreArrayRead(fv, &array)); 474 PetscCall(PetscDrawFlush(draw)); 475 PetscCall(PetscDrawPause(draw)); 476 PetscCall(PetscDrawSave(draw)); 477 } 478 if (Nf > 1) { 479 PetscCall(VecRestoreSubVector(v, fis, &fv)); 480 PetscCall(ISDestroy(&fis)); 481 PetscCall(DMDestroy(&fdm)); 482 } 483 } 484 PetscFunctionReturn(PETSC_SUCCESS); 485 } 486 487 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 488 { 489 DM dm; 490 PetscDraw draw; 491 PetscInt dim; 492 PetscBool isnull; 493 494 PetscFunctionBegin; 495 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 496 PetscCall(PetscDrawIsNull(draw, &isnull)); 497 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 498 499 PetscCall(VecGetDM(v, &dm)); 500 PetscCall(DMGetCoordinateDim(dm, &dim)); 501 switch (dim) { 502 case 1: 503 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 504 break; 505 case 2: 506 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 507 break; 508 default: 509 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 510 } 511 PetscFunctionReturn(PETSC_SUCCESS); 512 } 513 514 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 515 { 516 DM dm; 517 Vec locv; 518 const char *name; 519 PetscSection section; 520 PetscInt pStart, pEnd; 521 PetscInt numFields; 522 PetscViewerVTKFieldType ft; 523 524 PetscFunctionBegin; 525 PetscCall(VecGetDM(v, &dm)); 526 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 527 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 528 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 529 PetscCall(VecCopy(v, locv)); 530 PetscCall(DMGetLocalSection(dm, §ion)); 531 PetscCall(PetscSectionGetNumFields(section, &numFields)); 532 if (!numFields) { 533 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 534 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 535 } else { 536 PetscInt f; 537 538 for (f = 0; f < numFields; f++) { 539 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 540 if (ft == PETSC_VTK_INVALID) continue; 541 PetscCall(PetscObjectReference((PetscObject)locv)); 542 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 543 } 544 PetscCall(VecDestroy(&locv)); 545 } 546 PetscFunctionReturn(PETSC_SUCCESS); 547 } 548 549 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 550 { 551 DM dm; 552 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 553 554 PetscFunctionBegin; 555 PetscCall(VecGetDM(v, &dm)); 556 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 561 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 562 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 563 PetscInt i, numFields; 564 PetscObject fe; 565 PetscBool fem = PETSC_FALSE; 566 Vec locv = v; 567 const char *name; 568 PetscInt step; 569 PetscReal time; 570 571 PetscCall(DMGetNumFields(dm, &numFields)); 572 for (i = 0; i < numFields; i++) { 573 PetscCall(DMGetField(dm, i, NULL, &fe)); 574 if (fe->classid == PETSCFE_CLASSID) { 575 fem = PETSC_TRUE; 576 break; 577 } 578 } 579 if (fem) { 580 PetscObject isZero; 581 582 PetscCall(DMGetLocalVector(dm, &locv)); 583 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 584 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 585 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 586 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 587 PetscCall(VecCopy(v, locv)); 588 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 589 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 590 } 591 if (isvtk) { 592 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 593 } else if (ishdf5) { 594 #if defined(PETSC_HAVE_HDF5) 595 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 596 #else 597 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 598 #endif 599 } else if (isdraw) { 600 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 601 } else if (isglvis) { 602 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 603 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 604 PetscCall(VecView_GLVis(locv, viewer)); 605 } else if (iscgns) { 606 #if defined(PETSC_HAVE_CGNS) 607 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 608 #else 609 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 610 #endif 611 } 612 if (fem) { 613 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 614 PetscCall(DMRestoreLocalVector(dm, &locv)); 615 } 616 } else { 617 PetscBool isseq; 618 619 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 620 if (isseq) PetscCall(VecView_Seq(v, viewer)); 621 else PetscCall(VecView_MPI(v, viewer)); 622 } 623 PetscFunctionReturn(PETSC_SUCCESS); 624 } 625 626 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 627 { 628 DM dm; 629 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 630 631 PetscFunctionBegin; 632 PetscCall(VecGetDM(v, &dm)); 633 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 640 if (isvtk || isdraw || isglvis || iscgns) { 641 Vec locv; 642 PetscObject isZero; 643 const char *name; 644 645 PetscCall(DMGetLocalVector(dm, &locv)); 646 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 647 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 648 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 649 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 650 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 651 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 652 PetscCall(VecView_Plex_Local(locv, viewer)); 653 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 654 PetscCall(DMRestoreLocalVector(dm, &locv)); 655 } else if (ishdf5) { 656 #if defined(PETSC_HAVE_HDF5) 657 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 658 #else 659 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 660 #endif 661 } else if (isexodusii) { 662 #if defined(PETSC_HAVE_EXODUSII) 663 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 664 #else 665 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 666 #endif 667 } else { 668 PetscBool isseq; 669 670 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 671 if (isseq) PetscCall(VecView_Seq(v, viewer)); 672 else PetscCall(VecView_MPI(v, viewer)); 673 } 674 PetscFunctionReturn(PETSC_SUCCESS); 675 } 676 677 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 678 { 679 DM dm; 680 MPI_Comm comm; 681 PetscViewerFormat format; 682 Vec v; 683 PetscBool isvtk, ishdf5; 684 685 PetscFunctionBegin; 686 PetscCall(VecGetDM(originalv, &dm)); 687 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 688 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 689 PetscCall(PetscViewerGetFormat(viewer, &format)); 690 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 691 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 692 if (format == PETSC_VIEWER_NATIVE) { 693 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 694 /* this need a better fix */ 695 if (dm->useNatural) { 696 if (dm->sfNatural) { 697 const char *vecname; 698 PetscInt n, nroots; 699 700 PetscCall(VecGetLocalSize(originalv, &n)); 701 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 702 if (n == nroots) { 703 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 704 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 705 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 706 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 707 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 708 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 709 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 710 } else v = originalv; 711 } else v = originalv; 712 713 if (ishdf5) { 714 #if defined(PETSC_HAVE_HDF5) 715 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 716 #else 717 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 718 #endif 719 } else if (isvtk) { 720 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 721 } else { 722 PetscBool isseq; 723 724 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 725 if (isseq) PetscCall(VecView_Seq(v, viewer)); 726 else PetscCall(VecView_MPI(v, viewer)); 727 } 728 if (v != originalv) PetscCall(VecDestroy(&v)); 729 PetscFunctionReturn(PETSC_SUCCESS); 730 } 731 732 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 733 { 734 DM dm; 735 PetscBool ishdf5; 736 737 PetscFunctionBegin; 738 PetscCall(VecGetDM(v, &dm)); 739 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 740 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 741 if (ishdf5) { 742 DM dmBC; 743 Vec gv; 744 const char *name; 745 746 PetscCall(DMGetOutputDM(dm, &dmBC)); 747 PetscCall(DMGetGlobalVector(dmBC, &gv)); 748 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 749 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 750 PetscCall(VecLoad_Default(gv, viewer)); 751 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 752 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 753 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 754 } else PetscCall(VecLoad_Default(v, viewer)); 755 PetscFunctionReturn(PETSC_SUCCESS); 756 } 757 758 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 759 { 760 DM dm; 761 PetscBool ishdf5, isexodusii; 762 763 PetscFunctionBegin; 764 PetscCall(VecGetDM(v, &dm)); 765 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 766 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 767 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 768 if (ishdf5) { 769 #if defined(PETSC_HAVE_HDF5) 770 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 771 #else 772 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 773 #endif 774 } else if (isexodusii) { 775 #if defined(PETSC_HAVE_EXODUSII) 776 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 777 #else 778 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 779 #endif 780 } else PetscCall(VecLoad_Default(v, viewer)); 781 PetscFunctionReturn(PETSC_SUCCESS); 782 } 783 784 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 785 { 786 DM dm; 787 PetscViewerFormat format; 788 PetscBool ishdf5; 789 790 PetscFunctionBegin; 791 PetscCall(VecGetDM(originalv, &dm)); 792 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 793 PetscCall(PetscViewerGetFormat(viewer, &format)); 794 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 795 if (format == PETSC_VIEWER_NATIVE) { 796 if (dm->useNatural) { 797 if (dm->sfNatural) { 798 if (ishdf5) { 799 #if defined(PETSC_HAVE_HDF5) 800 Vec v; 801 const char *vecname; 802 803 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 804 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 805 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 806 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 807 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 808 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 809 PetscCall(VecDestroy(&v)); 810 #else 811 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 812 #endif 813 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 814 } 815 } else PetscCall(VecLoad_Default(originalv, viewer)); 816 } 817 PetscFunctionReturn(PETSC_SUCCESS); 818 } 819 820 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 821 { 822 PetscSection coordSection; 823 Vec coordinates; 824 DMLabel depthLabel, celltypeLabel; 825 const char *name[4]; 826 const PetscScalar *a; 827 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 828 829 PetscFunctionBegin; 830 PetscCall(DMGetDimension(dm, &dim)); 831 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 832 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 833 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 834 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 835 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 836 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 837 PetscCall(VecGetArrayRead(coordinates, &a)); 838 name[0] = "vertex"; 839 name[1] = "edge"; 840 name[dim - 1] = "face"; 841 name[dim] = "cell"; 842 for (c = cStart; c < cEnd; ++c) { 843 PetscInt *closure = NULL; 844 PetscInt closureSize, cl, ct; 845 846 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 847 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 848 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 849 PetscCall(PetscViewerASCIIPushTab(viewer)); 850 for (cl = 0; cl < closureSize * 2; cl += 2) { 851 PetscInt point = closure[cl], depth, dof, off, d, p; 852 853 if ((point < pStart) || (point >= pEnd)) continue; 854 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 855 if (!dof) continue; 856 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 857 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 858 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 859 for (p = 0; p < dof / dim; ++p) { 860 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 861 for (d = 0; d < dim; ++d) { 862 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 863 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 864 } 865 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 866 } 867 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 868 } 869 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 870 PetscCall(PetscViewerASCIIPopTab(viewer)); 871 } 872 PetscCall(VecRestoreArrayRead(coordinates, &a)); 873 PetscFunctionReturn(PETSC_SUCCESS); 874 } 875 876 typedef enum { 877 CS_CARTESIAN, 878 CS_POLAR, 879 CS_CYLINDRICAL, 880 CS_SPHERICAL 881 } CoordSystem; 882 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 883 884 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 885 { 886 PetscInt i; 887 888 PetscFunctionBegin; 889 if (dim > 3) { 890 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 891 } else { 892 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 893 894 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 895 switch (cs) { 896 case CS_CARTESIAN: 897 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 898 break; 899 case CS_POLAR: 900 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 901 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 902 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 903 break; 904 case CS_CYLINDRICAL: 905 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 906 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 907 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 908 trcoords[2] = coords[2]; 909 break; 910 case CS_SPHERICAL: 911 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 912 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 913 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 914 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 915 break; 916 } 917 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 918 } 919 PetscFunctionReturn(PETSC_SUCCESS); 920 } 921 922 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 923 { 924 DM_Plex *mesh = (DM_Plex *)dm->data; 925 DM cdm, cdmCell; 926 PetscSection coordSection, coordSectionCell; 927 Vec coordinates, coordinatesCell; 928 PetscViewerFormat format; 929 930 PetscFunctionBegin; 931 PetscCall(PetscViewerGetFormat(viewer, &format)); 932 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 933 const char *name; 934 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 935 PetscInt pStart, pEnd, p, numLabels, l; 936 PetscMPIInt rank, size; 937 938 PetscCall(DMGetCoordinateDM(dm, &cdm)); 939 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 940 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 941 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 942 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 943 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 944 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 945 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 946 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 947 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 948 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 949 PetscCall(DMGetDimension(dm, &dim)); 950 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 951 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 952 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 953 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 955 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 956 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 957 for (p = pStart; p < pEnd; ++p) { 958 PetscInt dof, off, s; 959 960 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 961 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 962 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 963 } 964 PetscCall(PetscViewerFlush(viewer)); 965 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 966 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 967 for (p = pStart; p < pEnd; ++p) { 968 PetscInt dof, off, c; 969 970 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 971 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 972 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])); 973 } 974 PetscCall(PetscViewerFlush(viewer)); 975 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 976 if (coordSection && coordinates) { 977 CoordSystem cs = CS_CARTESIAN; 978 const PetscScalar *array, *arrayCell = NULL; 979 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 980 PetscMPIInt rank; 981 const char *name; 982 983 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 984 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 985 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 986 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 987 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 988 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 989 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 990 pStart = PetscMin(pvStart, pcStart); 991 pEnd = PetscMax(pvEnd, pcEnd); 992 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 993 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 994 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 995 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 996 997 PetscCall(VecGetArrayRead(coordinates, &array)); 998 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 999 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1000 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1001 for (p = pStart; p < pEnd; ++p) { 1002 PetscInt dof, off; 1003 1004 if (p >= pvStart && p < pvEnd) { 1005 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1006 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1007 if (dof) { 1008 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1009 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1010 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1011 } 1012 } 1013 if (cdmCell && p >= pcStart && p < pcEnd) { 1014 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1015 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1016 if (dof) { 1017 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1018 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1019 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1020 } 1021 } 1022 } 1023 PetscCall(PetscViewerFlush(viewer)); 1024 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1025 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1026 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1027 } 1028 PetscCall(DMGetNumLabels(dm, &numLabels)); 1029 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1030 for (l = 0; l < numLabels; ++l) { 1031 DMLabel label; 1032 PetscBool isdepth; 1033 const char *name; 1034 1035 PetscCall(DMGetLabelName(dm, l, &name)); 1036 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1037 if (isdepth) continue; 1038 PetscCall(DMGetLabel(dm, name, &label)); 1039 PetscCall(DMLabelView(label, viewer)); 1040 } 1041 if (size > 1) { 1042 PetscSF sf; 1043 1044 PetscCall(DMGetPointSF(dm, &sf)); 1045 PetscCall(PetscSFView(sf, viewer)); 1046 } 1047 if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer)); 1048 PetscCall(PetscViewerFlush(viewer)); 1049 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1050 const char *name, *color; 1051 const char *defcolors[3] = {"gray", "orange", "green"}; 1052 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1053 char lname[PETSC_MAX_PATH_LEN]; 1054 PetscReal scale = 2.0; 1055 PetscReal tikzscale = 1.0; 1056 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1057 double tcoords[3]; 1058 PetscScalar *coords; 1059 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 1060 PetscMPIInt rank, size; 1061 char **names, **colors, **lcolors; 1062 PetscBool flg, lflg; 1063 PetscBT wp = NULL; 1064 PetscInt pEnd, pStart; 1065 1066 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1067 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1068 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1069 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1070 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1071 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1072 PetscCall(DMGetDimension(dm, &dim)); 1073 PetscCall(DMPlexGetDepth(dm, &depth)); 1074 PetscCall(DMGetNumLabels(dm, &numLabels)); 1075 numLabels = PetscMax(numLabels, 10); 1076 numColors = 10; 1077 numLColors = 10; 1078 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1079 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1080 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1081 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1082 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1083 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1084 n = 4; 1085 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1086 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1087 n = 4; 1088 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1089 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1090 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1091 if (!useLabels) numLabels = 0; 1092 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1093 if (!useColors) { 1094 numColors = 3; 1095 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1096 } 1097 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1098 if (!useColors) { 1099 numLColors = 4; 1100 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1101 } 1102 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1103 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1104 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1105 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1106 if (depth < dim) plotEdges = PETSC_FALSE; 1107 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1108 1109 /* filter points with labelvalue != labeldefaultvalue */ 1110 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1111 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1112 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1113 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1114 if (lflg) { 1115 DMLabel lbl; 1116 1117 PetscCall(DMGetLabel(dm, lname, &lbl)); 1118 if (lbl) { 1119 PetscInt val, defval; 1120 1121 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1122 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1123 for (c = pStart; c < pEnd; c++) { 1124 PetscInt *closure = NULL; 1125 PetscInt closureSize; 1126 1127 PetscCall(DMLabelGetValue(lbl, c, &val)); 1128 if (val == defval) continue; 1129 1130 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1131 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1132 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1133 } 1134 } 1135 } 1136 1137 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1138 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1139 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1140 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1141 \\documentclass[tikz]{standalone}\n\n\ 1142 \\usepackage{pgflibraryshapes}\n\ 1143 \\usetikzlibrary{backgrounds}\n\ 1144 \\usetikzlibrary{arrows}\n\ 1145 \\begin{document}\n")); 1146 if (size > 1) { 1147 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1148 for (p = 0; p < size; ++p) { 1149 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1150 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1151 } 1152 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1153 } 1154 if (drawHasse) { 1155 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1156 1157 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1158 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1168 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1169 } 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1171 1172 /* Plot vertices */ 1173 PetscCall(VecGetArray(coordinates, &coords)); 1174 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1175 for (v = vStart; v < vEnd; ++v) { 1176 PetscInt off, dof, d; 1177 PetscBool isLabeled = PETSC_FALSE; 1178 1179 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1180 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1181 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1182 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1183 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1184 for (d = 0; d < dof; ++d) { 1185 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1186 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1187 } 1188 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1189 if (dim == 3) { 1190 PetscReal tmp = tcoords[1]; 1191 tcoords[1] = tcoords[2]; 1192 tcoords[2] = -tmp; 1193 } 1194 for (d = 0; d < dof; ++d) { 1195 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1196 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1197 } 1198 if (drawHasse) color = colors[0 % numColors]; 1199 else color = colors[rank % numColors]; 1200 for (l = 0; l < numLabels; ++l) { 1201 PetscInt val; 1202 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1203 if (val >= 0) { 1204 color = lcolors[l % numLColors]; 1205 isLabeled = PETSC_TRUE; 1206 break; 1207 } 1208 } 1209 if (drawNumbers[0]) { 1210 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1211 } else if (drawColors[0]) { 1212 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1213 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1214 } 1215 PetscCall(VecRestoreArray(coordinates, &coords)); 1216 PetscCall(PetscViewerFlush(viewer)); 1217 /* Plot edges */ 1218 if (plotEdges) { 1219 PetscCall(VecGetArray(coordinates, &coords)); 1220 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1221 for (e = eStart; e < eEnd; ++e) { 1222 const PetscInt *cone; 1223 PetscInt coneSize, offA, offB, dof, d; 1224 1225 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1226 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1227 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1228 PetscCall(DMPlexGetCone(dm, e, &cone)); 1229 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1230 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1231 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1232 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1233 for (d = 0; d < dof; ++d) { 1234 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1235 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1236 } 1237 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1238 if (dim == 3) { 1239 PetscReal tmp = tcoords[1]; 1240 tcoords[1] = tcoords[2]; 1241 tcoords[2] = -tmp; 1242 } 1243 for (d = 0; d < dof; ++d) { 1244 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1245 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1246 } 1247 if (drawHasse) color = colors[1 % numColors]; 1248 else color = colors[rank % numColors]; 1249 for (l = 0; l < numLabels; ++l) { 1250 PetscInt val; 1251 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1252 if (val >= 0) { 1253 color = lcolors[l % numLColors]; 1254 break; 1255 } 1256 } 1257 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1258 } 1259 PetscCall(VecRestoreArray(coordinates, &coords)); 1260 PetscCall(PetscViewerFlush(viewer)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1262 } 1263 /* Plot cells */ 1264 if (dim == 3 || !drawNumbers[1]) { 1265 for (e = eStart; e < eEnd; ++e) { 1266 const PetscInt *cone; 1267 1268 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1269 color = colors[rank % numColors]; 1270 for (l = 0; l < numLabels; ++l) { 1271 PetscInt val; 1272 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1273 if (val >= 0) { 1274 color = lcolors[l % numLColors]; 1275 break; 1276 } 1277 } 1278 PetscCall(DMPlexGetCone(dm, e, &cone)); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1280 } 1281 } else { 1282 DMPolytopeType ct; 1283 1284 /* Drawing a 2D polygon */ 1285 for (c = cStart; c < cEnd; ++c) { 1286 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1287 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1288 if (DMPolytopeTypeIsHybrid(ct)) { 1289 const PetscInt *cone; 1290 PetscInt coneSize, e; 1291 1292 PetscCall(DMPlexGetCone(dm, c, &cone)); 1293 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1294 for (e = 0; e < coneSize; ++e) { 1295 const PetscInt *econe; 1296 1297 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1298 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)); 1299 } 1300 } else { 1301 PetscInt *closure = NULL; 1302 PetscInt closureSize, Nv = 0, v; 1303 1304 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1305 for (p = 0; p < closureSize * 2; p += 2) { 1306 const PetscInt point = closure[p]; 1307 1308 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1309 } 1310 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1311 for (v = 0; v <= Nv; ++v) { 1312 const PetscInt vertex = closure[v % Nv]; 1313 1314 if (v > 0) { 1315 if (plotEdges) { 1316 const PetscInt *edge; 1317 PetscInt endpoints[2], ne; 1318 1319 endpoints[0] = closure[v - 1]; 1320 endpoints[1] = vertex; 1321 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1322 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1323 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1324 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1325 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1326 } 1327 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1328 } 1329 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1330 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1331 } 1332 } 1333 } 1334 for (c = cStart; c < cEnd; ++c) { 1335 double ccoords[3] = {0.0, 0.0, 0.0}; 1336 PetscBool isLabeled = PETSC_FALSE; 1337 PetscScalar *cellCoords = NULL; 1338 const PetscScalar *array; 1339 PetscInt numCoords, cdim, d; 1340 PetscBool isDG; 1341 1342 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1343 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1344 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1345 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1346 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1347 for (p = 0; p < numCoords / cdim; ++p) { 1348 for (d = 0; d < cdim; ++d) { 1349 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1350 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1351 } 1352 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1353 if (cdim == 3) { 1354 PetscReal tmp = tcoords[1]; 1355 tcoords[1] = tcoords[2]; 1356 tcoords[2] = -tmp; 1357 } 1358 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1359 } 1360 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1361 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1362 for (d = 0; d < cdim; ++d) { 1363 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1364 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1365 } 1366 if (drawHasse) color = colors[depth % numColors]; 1367 else color = colors[rank % numColors]; 1368 for (l = 0; l < numLabels; ++l) { 1369 PetscInt val; 1370 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1371 if (val >= 0) { 1372 color = lcolors[l % numLColors]; 1373 isLabeled = PETSC_TRUE; 1374 break; 1375 } 1376 } 1377 if (drawNumbers[dim]) { 1378 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1379 } else if (drawColors[dim]) { 1380 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1381 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1382 } 1383 if (drawHasse) { 1384 color = colors[depth % numColors]; 1385 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1386 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1387 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1388 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1389 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1390 1391 color = colors[1 % numColors]; 1392 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1393 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1394 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1396 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1397 1398 color = colors[0 % numColors]; 1399 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1403 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1404 1405 for (p = pStart; p < pEnd; ++p) { 1406 const PetscInt *cone; 1407 PetscInt coneSize, cp; 1408 1409 PetscCall(DMPlexGetCone(dm, p, &cone)); 1410 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1411 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1412 } 1413 } 1414 PetscCall(PetscViewerFlush(viewer)); 1415 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1417 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1418 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1419 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1420 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1421 PetscCall(PetscFree3(names, colors, lcolors)); 1422 PetscCall(PetscBTDestroy(&wp)); 1423 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1424 Vec cown, acown; 1425 VecScatter sct; 1426 ISLocalToGlobalMapping g2l; 1427 IS gid, acis; 1428 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1429 MPI_Group ggroup, ngroup; 1430 PetscScalar *array, nid; 1431 const PetscInt *idxs; 1432 PetscInt *idxs2, *start, *adjacency, *work; 1433 PetscInt64 lm[3], gm[3]; 1434 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1435 PetscMPIInt d1, d2, rank; 1436 1437 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1438 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1439 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1440 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1441 #endif 1442 if (ncomm != MPI_COMM_NULL) { 1443 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1444 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1445 d1 = 0; 1446 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1447 nid = d2; 1448 PetscCallMPI(MPI_Group_free(&ggroup)); 1449 PetscCallMPI(MPI_Group_free(&ngroup)); 1450 PetscCallMPI(MPI_Comm_free(&ncomm)); 1451 } else nid = 0.0; 1452 1453 /* Get connectivity */ 1454 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1455 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1456 1457 /* filter overlapped local cells */ 1458 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1459 PetscCall(ISGetIndices(gid, &idxs)); 1460 PetscCall(ISGetLocalSize(gid, &cum)); 1461 PetscCall(PetscMalloc1(cum, &idxs2)); 1462 for (c = cStart, cum = 0; c < cEnd; c++) { 1463 if (idxs[c - cStart] < 0) continue; 1464 idxs2[cum++] = idxs[c - cStart]; 1465 } 1466 PetscCall(ISRestoreIndices(gid, &idxs)); 1467 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1468 PetscCall(ISDestroy(&gid)); 1469 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1470 1471 /* support for node-aware cell locality */ 1472 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1473 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1474 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1475 PetscCall(VecGetArray(cown, &array)); 1476 for (c = 0; c < numVertices; c++) array[c] = nid; 1477 PetscCall(VecRestoreArray(cown, &array)); 1478 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1479 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1480 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1481 PetscCall(ISDestroy(&acis)); 1482 PetscCall(VecScatterDestroy(&sct)); 1483 PetscCall(VecDestroy(&cown)); 1484 1485 /* compute edgeCut */ 1486 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1487 PetscCall(PetscMalloc1(cum, &work)); 1488 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1489 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1490 PetscCall(ISDestroy(&gid)); 1491 PetscCall(VecGetArray(acown, &array)); 1492 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1493 PetscInt totl; 1494 1495 totl = start[c + 1] - start[c]; 1496 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1497 for (i = 0; i < totl; i++) { 1498 if (work[i] < 0) { 1499 ect += 1; 1500 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1501 } 1502 } 1503 } 1504 PetscCall(PetscFree(work)); 1505 PetscCall(VecRestoreArray(acown, &array)); 1506 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1507 lm[1] = -numVertices; 1508 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1510 lm[0] = ect; /* edgeCut */ 1511 lm[1] = ectn; /* node-aware edgeCut */ 1512 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1513 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1514 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1515 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1516 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1517 #else 1518 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1519 #endif 1520 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1521 PetscCall(PetscFree(start)); 1522 PetscCall(PetscFree(adjacency)); 1523 PetscCall(VecDestroy(&acown)); 1524 } else { 1525 const char *name; 1526 PetscInt *sizes, *hybsizes, *ghostsizes; 1527 PetscInt locDepth, depth, cellHeight, dim, d; 1528 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1529 PetscInt numLabels, l, maxSize = 17; 1530 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1531 MPI_Comm comm; 1532 PetscMPIInt size, rank; 1533 1534 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1535 PetscCallMPI(MPI_Comm_size(comm, &size)); 1536 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1537 PetscCall(DMGetDimension(dm, &dim)); 1538 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1539 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1540 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1541 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1542 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1543 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1544 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1545 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1546 gcNum = gcEnd - gcStart; 1547 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1548 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1549 for (d = 0; d <= depth; d++) { 1550 PetscInt Nc[2] = {0, 0}, ict; 1551 1552 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1553 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1554 ict = ct0; 1555 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1556 ct0 = (DMPolytopeType)ict; 1557 for (p = pStart; p < pEnd; ++p) { 1558 DMPolytopeType ct; 1559 1560 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1561 if (ct == ct0) ++Nc[0]; 1562 else ++Nc[1]; 1563 } 1564 if (size < maxSize) { 1565 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1566 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1567 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1568 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1569 for (p = 0; p < size; ++p) { 1570 if (rank == 0) { 1571 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1572 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1573 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1574 } 1575 } 1576 } else { 1577 PetscInt locMinMax[2]; 1578 1579 locMinMax[0] = Nc[0] + Nc[1]; 1580 locMinMax[1] = Nc[0] + Nc[1]; 1581 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1582 locMinMax[0] = Nc[1]; 1583 locMinMax[1] = Nc[1]; 1584 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1585 if (d == depth) { 1586 locMinMax[0] = gcNum; 1587 locMinMax[1] = gcNum; 1588 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1589 } 1590 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1591 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1592 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1593 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1594 } 1595 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1596 } 1597 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1598 { 1599 const PetscReal *maxCell; 1600 const PetscReal *L; 1601 PetscBool localized; 1602 1603 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1604 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1605 if (L || localized) { 1606 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1607 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1608 if (L) { 1609 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1610 for (d = 0; d < dim; ++d) { 1611 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1612 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1613 } 1614 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1615 } 1616 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1617 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1618 } 1619 } 1620 PetscCall(DMGetNumLabels(dm, &numLabels)); 1621 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1622 for (l = 0; l < numLabels; ++l) { 1623 DMLabel label; 1624 const char *name; 1625 IS valueIS; 1626 const PetscInt *values; 1627 PetscInt numValues, v; 1628 1629 PetscCall(DMGetLabelName(dm, l, &name)); 1630 PetscCall(DMGetLabel(dm, name, &label)); 1631 PetscCall(DMLabelGetNumValues(label, &numValues)); 1632 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1633 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1634 PetscCall(ISGetIndices(valueIS, &values)); 1635 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1636 for (v = 0; v < numValues; ++v) { 1637 PetscInt size; 1638 1639 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1640 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1641 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1642 } 1643 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1644 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1645 PetscCall(ISRestoreIndices(valueIS, &values)); 1646 PetscCall(ISDestroy(&valueIS)); 1647 } 1648 { 1649 char **labelNames; 1650 PetscInt Nl = numLabels; 1651 PetscBool flg; 1652 1653 PetscCall(PetscMalloc1(Nl, &labelNames)); 1654 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1655 for (l = 0; l < Nl; ++l) { 1656 DMLabel label; 1657 1658 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1659 if (flg) { 1660 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1661 PetscCall(DMLabelView(label, viewer)); 1662 } 1663 PetscCall(PetscFree(labelNames[l])); 1664 } 1665 PetscCall(PetscFree(labelNames)); 1666 } 1667 /* If no fields are specified, people do not want to see adjacency */ 1668 if (dm->Nf) { 1669 PetscInt f; 1670 1671 for (f = 0; f < dm->Nf; ++f) { 1672 const char *name; 1673 1674 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1675 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1676 PetscCall(PetscViewerASCIIPushTab(viewer)); 1677 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1678 if (dm->fields[f].adjacency[0]) { 1679 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1680 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1681 } else { 1682 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1683 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1684 } 1685 PetscCall(PetscViewerASCIIPopTab(viewer)); 1686 } 1687 } 1688 PetscCall(DMGetCoarseDM(dm, &cdm)); 1689 if (cdm) { 1690 PetscCall(PetscViewerASCIIPushTab(viewer)); 1691 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1692 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1693 PetscCall(PetscViewerASCIIPopTab(viewer)); 1694 } 1695 } 1696 PetscFunctionReturn(PETSC_SUCCESS); 1697 } 1698 1699 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1700 { 1701 DMPolytopeType ct; 1702 PetscMPIInt rank; 1703 PetscInt cdim; 1704 1705 PetscFunctionBegin; 1706 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1707 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1708 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1709 switch (ct) { 1710 case DM_POLYTOPE_SEGMENT: 1711 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1712 switch (cdim) { 1713 case 1: { 1714 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1715 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1716 1717 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1718 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1719 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1720 } break; 1721 case 2: { 1722 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1723 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1724 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1725 1726 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1727 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)); 1728 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)); 1729 } break; 1730 default: 1731 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1732 } 1733 break; 1734 case DM_POLYTOPE_TRIANGLE: 1735 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)); 1736 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1737 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1738 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1739 break; 1740 case DM_POLYTOPE_QUADRILATERAL: 1741 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)); 1742 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)); 1743 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1744 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1745 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1746 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1747 break; 1748 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1749 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)); 1750 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)); 1751 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1752 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1753 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1754 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1755 break; 1756 case DM_POLYTOPE_FV_GHOST: 1757 break; 1758 default: 1759 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1760 } 1761 PetscFunctionReturn(PETSC_SUCCESS); 1762 } 1763 1764 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1765 { 1766 PetscReal centroid[2] = {0., 0.}; 1767 PetscMPIInt rank; 1768 PetscInt fillColor; 1769 1770 PetscFunctionBegin; 1771 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1772 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1773 for (PetscInt v = 0; v < Nv; ++v) { 1774 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1775 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1776 } 1777 for (PetscInt e = 0; e < Nv; ++e) { 1778 refCoords[0] = refVertices[e * 2 + 0]; 1779 refCoords[1] = refVertices[e * 2 + 1]; 1780 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1781 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1782 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1783 } 1784 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1785 for (PetscInt d = 0; d < edgeDiv; ++d) { 1786 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)); 1787 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1788 } 1789 } 1790 PetscFunctionReturn(PETSC_SUCCESS); 1791 } 1792 1793 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1794 { 1795 DMPolytopeType ct; 1796 1797 PetscFunctionBegin; 1798 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1799 switch (ct) { 1800 case DM_POLYTOPE_TRIANGLE: { 1801 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1802 1803 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1804 } break; 1805 case DM_POLYTOPE_QUADRILATERAL: { 1806 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1807 1808 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1809 } break; 1810 default: 1811 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1812 } 1813 PetscFunctionReturn(PETSC_SUCCESS); 1814 } 1815 1816 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1817 { 1818 PetscDraw draw; 1819 DM cdm; 1820 PetscSection coordSection; 1821 Vec coordinates; 1822 PetscReal xyl[3], xyr[3]; 1823 PetscReal *refCoords, *edgeCoords; 1824 PetscBool isnull, drawAffine; 1825 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1826 1827 PetscFunctionBegin; 1828 PetscCall(DMGetCoordinateDim(dm, &dim)); 1829 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1830 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1831 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1832 edgeDiv = cDegree + 1; 1833 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1834 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1835 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1836 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1837 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1838 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1839 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1840 1841 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1842 PetscCall(PetscDrawIsNull(draw, &isnull)); 1843 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1844 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1845 1846 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1847 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1848 PetscCall(PetscDrawClear(draw)); 1849 1850 for (c = cStart; c < cEnd; ++c) { 1851 PetscScalar *coords = NULL; 1852 const PetscScalar *coords_arr; 1853 PetscInt numCoords; 1854 PetscBool isDG; 1855 1856 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1857 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1858 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1859 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1860 } 1861 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1862 PetscCall(PetscDrawFlush(draw)); 1863 PetscCall(PetscDrawPause(draw)); 1864 PetscCall(PetscDrawSave(draw)); 1865 PetscFunctionReturn(PETSC_SUCCESS); 1866 } 1867 1868 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1869 { 1870 DM odm = dm, rdm = dm, cdm; 1871 PetscFE fe; 1872 PetscSpace sp; 1873 PetscClassId id; 1874 PetscInt degree; 1875 PetscBool hoView = PETSC_TRUE; 1876 1877 PetscFunctionBegin; 1878 PetscObjectOptionsBegin((PetscObject)dm); 1879 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1880 PetscOptionsEnd(); 1881 PetscCall(PetscObjectReference((PetscObject)dm)); 1882 *hdm = dm; 1883 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1884 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1885 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1886 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1887 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1888 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1889 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1890 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1891 DM cdm, rcdm; 1892 Mat In; 1893 Vec cl, rcl; 1894 1895 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1896 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1897 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1898 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1899 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1900 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1901 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1902 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1903 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1904 PetscCall(MatMult(In, cl, rcl)); 1905 PetscCall(MatDestroy(&In)); 1906 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1907 PetscCall(DMDestroy(&odm)); 1908 odm = rdm; 1909 } 1910 *hdm = rdm; 1911 PetscFunctionReturn(PETSC_SUCCESS); 1912 } 1913 1914 #if defined(PETSC_HAVE_EXODUSII) 1915 #include <exodusII.h> 1916 #include <petscviewerexodusii.h> 1917 #endif 1918 1919 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1920 { 1921 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1922 char name[PETSC_MAX_PATH_LEN]; 1923 1924 PetscFunctionBegin; 1925 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1926 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1927 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1928 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1929 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1930 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1931 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1932 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1933 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1934 if (iascii) { 1935 PetscViewerFormat format; 1936 PetscCall(PetscViewerGetFormat(viewer, &format)); 1937 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1938 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1939 } else if (ishdf5) { 1940 #if defined(PETSC_HAVE_HDF5) 1941 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1942 #else 1943 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1944 #endif 1945 } else if (isvtk) { 1946 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1947 } else if (isdraw) { 1948 DM hdm; 1949 1950 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1951 PetscCall(DMPlexView_Draw(hdm, viewer)); 1952 PetscCall(DMDestroy(&hdm)); 1953 } else if (isglvis) { 1954 PetscCall(DMPlexView_GLVis(dm, viewer)); 1955 #if defined(PETSC_HAVE_EXODUSII) 1956 } else if (isexodus) { 1957 /* 1958 exodusII requires that all sets be part of exactly one cell set. 1959 If the dm does not have a "Cell Sets" label defined, we create one 1960 with ID 1, containing all cells. 1961 Note that if the Cell Sets label is defined but does not cover all cells, 1962 we may still have a problem. This should probably be checked here or in the viewer; 1963 */ 1964 PetscInt numCS; 1965 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1966 if (!numCS) { 1967 PetscInt cStart, cEnd, c; 1968 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1969 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1970 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1971 } 1972 PetscCall(DMView_PlexExodusII(dm, viewer)); 1973 #endif 1974 #if defined(PETSC_HAVE_CGNS) 1975 } else if (iscgns) { 1976 PetscCall(DMView_PlexCGNS(dm, viewer)); 1977 #endif 1978 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1979 /* Optionally view the partition */ 1980 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1981 if (flg) { 1982 Vec ranks; 1983 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1984 PetscCall(VecView(ranks, viewer)); 1985 PetscCall(VecDestroy(&ranks)); 1986 } 1987 /* Optionally view a label */ 1988 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1989 if (flg) { 1990 DMLabel label; 1991 Vec val; 1992 1993 PetscCall(DMGetLabel(dm, name, &label)); 1994 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1995 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1996 PetscCall(VecView(val, viewer)); 1997 PetscCall(VecDestroy(&val)); 1998 } 1999 PetscFunctionReturn(PETSC_SUCCESS); 2000 } 2001 2002 /*@ 2003 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2004 2005 Collective 2006 2007 Input Parameters: 2008 + dm - The `DM` whose topology is to be saved 2009 - viewer - The `PetscViewer` to save it in 2010 2011 Level: advanced 2012 2013 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2014 @*/ 2015 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2016 { 2017 PetscBool ishdf5; 2018 2019 PetscFunctionBegin; 2020 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2021 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2022 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2023 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2024 if (ishdf5) { 2025 #if defined(PETSC_HAVE_HDF5) 2026 PetscViewerFormat format; 2027 PetscCall(PetscViewerGetFormat(viewer, &format)); 2028 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2029 IS globalPointNumbering; 2030 2031 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2032 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2033 PetscCall(ISDestroy(&globalPointNumbering)); 2034 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2035 #else 2036 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2037 #endif 2038 } 2039 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2040 PetscFunctionReturn(PETSC_SUCCESS); 2041 } 2042 2043 /*@ 2044 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2045 2046 Collective 2047 2048 Input Parameters: 2049 + dm - The `DM` whose coordinates are to be saved 2050 - viewer - The `PetscViewer` for saving 2051 2052 Level: advanced 2053 2054 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2055 @*/ 2056 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2057 { 2058 PetscBool ishdf5; 2059 2060 PetscFunctionBegin; 2061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2062 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2063 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2064 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2065 if (ishdf5) { 2066 #if defined(PETSC_HAVE_HDF5) 2067 PetscViewerFormat format; 2068 PetscCall(PetscViewerGetFormat(viewer, &format)); 2069 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2070 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2071 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2072 #else 2073 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2074 #endif 2075 } 2076 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2077 PetscFunctionReturn(PETSC_SUCCESS); 2078 } 2079 2080 /*@ 2081 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2082 2083 Collective 2084 2085 Input Parameters: 2086 + dm - The `DM` whose labels are to be saved 2087 - viewer - The `PetscViewer` for saving 2088 2089 Level: advanced 2090 2091 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2092 @*/ 2093 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2094 { 2095 PetscBool ishdf5; 2096 2097 PetscFunctionBegin; 2098 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2099 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2100 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2101 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2102 if (ishdf5) { 2103 #if defined(PETSC_HAVE_HDF5) 2104 IS globalPointNumbering; 2105 PetscViewerFormat format; 2106 2107 PetscCall(PetscViewerGetFormat(viewer, &format)); 2108 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2109 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2110 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2111 PetscCall(ISDestroy(&globalPointNumbering)); 2112 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2113 #else 2114 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2115 #endif 2116 } 2117 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2118 PetscFunctionReturn(PETSC_SUCCESS); 2119 } 2120 2121 /*@ 2122 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2123 2124 Collective 2125 2126 Input Parameters: 2127 + dm - The `DM` that contains the topology on which the section to be saved is defined 2128 . viewer - The `PetscViewer` for saving 2129 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2130 2131 Level: advanced 2132 2133 Notes: 2134 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. 2135 2136 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. 2137 2138 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2139 @*/ 2140 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2141 { 2142 PetscBool ishdf5; 2143 2144 PetscFunctionBegin; 2145 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2146 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2147 if (!sectiondm) sectiondm = dm; 2148 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2149 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2150 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2151 if (ishdf5) { 2152 #if defined(PETSC_HAVE_HDF5) 2153 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2154 #else 2155 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2156 #endif 2157 } 2158 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2159 PetscFunctionReturn(PETSC_SUCCESS); 2160 } 2161 2162 /*@ 2163 DMPlexGlobalVectorView - Saves a global vector 2164 2165 Collective 2166 2167 Input Parameters: 2168 + dm - The `DM` that represents the topology 2169 . viewer - The `PetscViewer` to save data with 2170 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2171 - vec - The global vector to be saved 2172 2173 Level: advanced 2174 2175 Notes: 2176 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. 2177 2178 Calling sequence: 2179 .vb 2180 DMCreate(PETSC_COMM_WORLD, &dm); 2181 DMSetType(dm, DMPLEX); 2182 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2183 DMClone(dm, §iondm); 2184 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2185 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2186 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2187 PetscSectionSetChart(section, pStart, pEnd); 2188 PetscSectionSetUp(section); 2189 DMSetLocalSection(sectiondm, section); 2190 PetscSectionDestroy(§ion); 2191 DMGetGlobalVector(sectiondm, &vec); 2192 PetscObjectSetName((PetscObject)vec, "vec_name"); 2193 DMPlexTopologyView(dm, viewer); 2194 DMPlexSectionView(dm, viewer, sectiondm); 2195 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2196 DMRestoreGlobalVector(sectiondm, &vec); 2197 DMDestroy(§iondm); 2198 DMDestroy(&dm); 2199 .ve 2200 2201 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2202 @*/ 2203 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2204 { 2205 PetscBool ishdf5; 2206 2207 PetscFunctionBegin; 2208 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2209 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2210 if (!sectiondm) sectiondm = dm; 2211 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2212 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2213 /* Check consistency */ 2214 { 2215 PetscSection section; 2216 PetscBool includesConstraints; 2217 PetscInt m, m1; 2218 2219 PetscCall(VecGetLocalSize(vec, &m1)); 2220 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2221 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2222 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2223 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2224 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2225 } 2226 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2227 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2228 if (ishdf5) { 2229 #if defined(PETSC_HAVE_HDF5) 2230 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2231 #else 2232 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2233 #endif 2234 } 2235 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2236 PetscFunctionReturn(PETSC_SUCCESS); 2237 } 2238 2239 /*@ 2240 DMPlexLocalVectorView - Saves a local vector 2241 2242 Collective 2243 2244 Input Parameters: 2245 + dm - The `DM` that represents the topology 2246 . viewer - The `PetscViewer` to save data with 2247 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2248 - vec - The local vector to be saved 2249 2250 Level: advanced 2251 2252 Note: 2253 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. 2254 2255 Calling sequence: 2256 .vb 2257 DMCreate(PETSC_COMM_WORLD, &dm); 2258 DMSetType(dm, DMPLEX); 2259 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2260 DMClone(dm, §iondm); 2261 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2262 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2263 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2264 PetscSectionSetChart(section, pStart, pEnd); 2265 PetscSectionSetUp(section); 2266 DMSetLocalSection(sectiondm, section); 2267 DMGetLocalVector(sectiondm, &vec); 2268 PetscObjectSetName((PetscObject)vec, "vec_name"); 2269 DMPlexTopologyView(dm, viewer); 2270 DMPlexSectionView(dm, viewer, sectiondm); 2271 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2272 DMRestoreLocalVector(sectiondm, &vec); 2273 DMDestroy(§iondm); 2274 DMDestroy(&dm); 2275 .ve 2276 2277 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2278 @*/ 2279 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2280 { 2281 PetscBool ishdf5; 2282 2283 PetscFunctionBegin; 2284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2285 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2286 if (!sectiondm) sectiondm = dm; 2287 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2288 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2289 /* Check consistency */ 2290 { 2291 PetscSection section; 2292 PetscBool includesConstraints; 2293 PetscInt m, m1; 2294 2295 PetscCall(VecGetLocalSize(vec, &m1)); 2296 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2297 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2298 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2299 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2300 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2301 } 2302 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2303 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2304 if (ishdf5) { 2305 #if defined(PETSC_HAVE_HDF5) 2306 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2307 #else 2308 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2309 #endif 2310 } 2311 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2312 PetscFunctionReturn(PETSC_SUCCESS); 2313 } 2314 2315 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2316 { 2317 PetscBool ishdf5; 2318 2319 PetscFunctionBegin; 2320 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2321 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2322 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2323 if (ishdf5) { 2324 #if defined(PETSC_HAVE_HDF5) 2325 PetscViewerFormat format; 2326 PetscCall(PetscViewerGetFormat(viewer, &format)); 2327 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2328 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2329 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2330 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2331 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2332 PetscFunctionReturn(PETSC_SUCCESS); 2333 #else 2334 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2335 #endif 2336 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2337 } 2338 2339 /*@ 2340 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2341 2342 Collective 2343 2344 Input Parameters: 2345 + dm - The `DM` into which the topology is loaded 2346 - viewer - The `PetscViewer` for the saved topology 2347 2348 Output Parameter: 2349 . 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 2350 2351 Level: advanced 2352 2353 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2354 `PetscViewer`, `PetscSF` 2355 @*/ 2356 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2357 { 2358 PetscBool ishdf5; 2359 2360 PetscFunctionBegin; 2361 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2362 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2363 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2364 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2365 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2366 if (ishdf5) { 2367 #if defined(PETSC_HAVE_HDF5) 2368 PetscViewerFormat format; 2369 PetscCall(PetscViewerGetFormat(viewer, &format)); 2370 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2371 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2372 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2373 #else 2374 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2375 #endif 2376 } 2377 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2378 PetscFunctionReturn(PETSC_SUCCESS); 2379 } 2380 2381 /*@ 2382 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2383 2384 Collective 2385 2386 Input Parameters: 2387 + dm - The `DM` into which the coordinates are loaded 2388 . viewer - The `PetscViewer` for the saved coordinates 2389 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2390 2391 Level: advanced 2392 2393 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2394 `PetscSF`, `PetscViewer` 2395 @*/ 2396 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2397 { 2398 PetscBool ishdf5; 2399 2400 PetscFunctionBegin; 2401 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2402 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2403 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2404 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2405 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2406 if (ishdf5) { 2407 #if defined(PETSC_HAVE_HDF5) 2408 PetscViewerFormat format; 2409 PetscCall(PetscViewerGetFormat(viewer, &format)); 2410 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2411 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2412 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2413 #else 2414 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2415 #endif 2416 } 2417 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2418 PetscFunctionReturn(PETSC_SUCCESS); 2419 } 2420 2421 /*@ 2422 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2423 2424 Collective 2425 2426 Input Parameters: 2427 + dm - The `DM` into which the labels are loaded 2428 . viewer - The `PetscViewer` for the saved labels 2429 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2430 2431 Level: advanced 2432 2433 Note: 2434 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2435 2436 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2437 `PetscSF`, `PetscViewer` 2438 @*/ 2439 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2440 { 2441 PetscBool ishdf5; 2442 2443 PetscFunctionBegin; 2444 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2445 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2446 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2447 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2448 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2449 if (ishdf5) { 2450 #if defined(PETSC_HAVE_HDF5) 2451 PetscViewerFormat format; 2452 2453 PetscCall(PetscViewerGetFormat(viewer, &format)); 2454 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2455 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2456 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2457 #else 2458 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2459 #endif 2460 } 2461 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2462 PetscFunctionReturn(PETSC_SUCCESS); 2463 } 2464 2465 /*@ 2466 DMPlexSectionLoad - Loads section into a `DMPLEX` 2467 2468 Collective 2469 2470 Input Parameters: 2471 + dm - The `DM` that represents the topology 2472 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2473 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2474 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2475 2476 Output Parameters: 2477 + 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) 2478 - 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) 2479 2480 Level: advanced 2481 2482 Notes: 2483 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. 2484 2485 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. 2486 2487 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. 2488 2489 Example using 2 processes: 2490 .vb 2491 NX (number of points on dm): 4 2492 sectionA : the on-disk section 2493 vecA : a vector associated with sectionA 2494 sectionB : sectiondm's local section constructed in this function 2495 vecB (local) : a vector associated with sectiondm's local section 2496 vecB (global) : a vector associated with sectiondm's global section 2497 2498 rank 0 rank 1 2499 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2500 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2501 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2502 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2503 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2504 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2505 sectionB->atlasDof : 1 0 1 | 1 3 2506 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2507 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2508 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2509 .ve 2510 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2511 2512 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2513 @*/ 2514 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2515 { 2516 PetscBool ishdf5; 2517 2518 PetscFunctionBegin; 2519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2520 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2521 if (!sectiondm) sectiondm = dm; 2522 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2523 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2524 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2525 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2526 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2527 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2528 if (ishdf5) { 2529 #if defined(PETSC_HAVE_HDF5) 2530 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2531 #else 2532 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2533 #endif 2534 } 2535 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2536 PetscFunctionReturn(PETSC_SUCCESS); 2537 } 2538 2539 /*@ 2540 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2541 2542 Collective 2543 2544 Input Parameters: 2545 + dm - The `DM` that represents the topology 2546 . viewer - The `PetscViewer` that represents the on-disk vector data 2547 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2548 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2549 - vec - The global vector to set values of 2550 2551 Level: advanced 2552 2553 Notes: 2554 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. 2555 2556 Calling sequence: 2557 .vb 2558 DMCreate(PETSC_COMM_WORLD, &dm); 2559 DMSetType(dm, DMPLEX); 2560 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2561 DMPlexTopologyLoad(dm, viewer, &sfX); 2562 DMClone(dm, §iondm); 2563 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2564 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2565 DMGetGlobalVector(sectiondm, &vec); 2566 PetscObjectSetName((PetscObject)vec, "vec_name"); 2567 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2568 DMRestoreGlobalVector(sectiondm, &vec); 2569 PetscSFDestroy(&gsf); 2570 PetscSFDestroy(&sfX); 2571 DMDestroy(§iondm); 2572 DMDestroy(&dm); 2573 .ve 2574 2575 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2576 `PetscSF`, `PetscViewer` 2577 @*/ 2578 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2579 { 2580 PetscBool ishdf5; 2581 2582 PetscFunctionBegin; 2583 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2584 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2585 if (!sectiondm) sectiondm = dm; 2586 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2587 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2588 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2589 /* Check consistency */ 2590 { 2591 PetscSection section; 2592 PetscBool includesConstraints; 2593 PetscInt m, m1; 2594 2595 PetscCall(VecGetLocalSize(vec, &m1)); 2596 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2597 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2598 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2599 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2600 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2601 } 2602 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2603 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2604 if (ishdf5) { 2605 #if defined(PETSC_HAVE_HDF5) 2606 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2607 #else 2608 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2609 #endif 2610 } 2611 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2612 PetscFunctionReturn(PETSC_SUCCESS); 2613 } 2614 2615 /*@ 2616 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2617 2618 Collective 2619 2620 Input Parameters: 2621 + dm - The `DM` that represents the topology 2622 . viewer - The `PetscViewer` that represents the on-disk vector data 2623 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2624 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2625 - vec - The local vector to set values of 2626 2627 Level: advanced 2628 2629 Notes: 2630 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. 2631 2632 Calling sequence: 2633 .vb 2634 DMCreate(PETSC_COMM_WORLD, &dm); 2635 DMSetType(dm, DMPLEX); 2636 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2637 DMPlexTopologyLoad(dm, viewer, &sfX); 2638 DMClone(dm, §iondm); 2639 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2640 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2641 DMGetLocalVector(sectiondm, &vec); 2642 PetscObjectSetName((PetscObject)vec, "vec_name"); 2643 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2644 DMRestoreLocalVector(sectiondm, &vec); 2645 PetscSFDestroy(&lsf); 2646 PetscSFDestroy(&sfX); 2647 DMDestroy(§iondm); 2648 DMDestroy(&dm); 2649 .ve 2650 2651 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2652 `PetscSF`, `PetscViewer` 2653 @*/ 2654 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2655 { 2656 PetscBool ishdf5; 2657 2658 PetscFunctionBegin; 2659 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2660 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2661 if (!sectiondm) sectiondm = dm; 2662 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2663 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2664 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2665 /* Check consistency */ 2666 { 2667 PetscSection section; 2668 PetscBool includesConstraints; 2669 PetscInt m, m1; 2670 2671 PetscCall(VecGetLocalSize(vec, &m1)); 2672 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2673 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2674 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2675 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2676 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2677 } 2678 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2679 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2680 if (ishdf5) { 2681 #if defined(PETSC_HAVE_HDF5) 2682 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2683 #else 2684 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2685 #endif 2686 } 2687 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2688 PetscFunctionReturn(PETSC_SUCCESS); 2689 } 2690 2691 PetscErrorCode DMDestroy_Plex(DM dm) 2692 { 2693 DM_Plex *mesh = (DM_Plex *)dm->data; 2694 2695 PetscFunctionBegin; 2696 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2697 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2698 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2699 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2700 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2701 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2702 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2703 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2704 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2705 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2706 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2707 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2708 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2709 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2710 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2711 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2712 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2713 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2714 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2715 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2716 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2717 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2718 PetscCall(PetscFree(mesh->cones)); 2719 PetscCall(PetscFree(mesh->coneOrientations)); 2720 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2721 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2722 PetscCall(PetscFree(mesh->supports)); 2723 PetscCall(PetscFree(mesh->cellTypes)); 2724 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2725 PetscCall(PetscFree(mesh->tetgenOpts)); 2726 PetscCall(PetscFree(mesh->triangleOpts)); 2727 PetscCall(PetscFree(mesh->transformType)); 2728 PetscCall(PetscFree(mesh->distributionName)); 2729 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2730 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2731 PetscCall(ISDestroy(&mesh->subpointIS)); 2732 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2733 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2734 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2735 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2736 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2737 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2738 PetscCall(ISDestroy(&mesh->anchorIS)); 2739 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2740 PetscCall(PetscFree(mesh->parents)); 2741 PetscCall(PetscFree(mesh->childIDs)); 2742 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2743 PetscCall(PetscFree(mesh->children)); 2744 PetscCall(DMDestroy(&mesh->referenceTree)); 2745 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2746 PetscCall(PetscFree(mesh->neighbors)); 2747 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2748 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2749 PetscCall(PetscFree(mesh)); 2750 PetscFunctionReturn(PETSC_SUCCESS); 2751 } 2752 2753 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2754 { 2755 PetscSection sectionGlobal, sectionLocal; 2756 PetscInt bs = -1, mbs; 2757 PetscInt localSize, localStart = 0; 2758 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2759 MatType mtype; 2760 ISLocalToGlobalMapping ltog; 2761 2762 PetscFunctionBegin; 2763 PetscCall(MatInitializePackage()); 2764 mtype = dm->mattype; 2765 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2766 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2767 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2768 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2769 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2770 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2771 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2772 PetscCall(MatSetType(*J, mtype)); 2773 PetscCall(MatSetFromOptions(*J)); 2774 PetscCall(MatGetBlockSize(*J, &mbs)); 2775 if (mbs > 1) bs = mbs; 2776 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2777 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2778 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2779 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2780 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2781 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2782 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2783 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2784 if (!isShell) { 2785 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2786 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2787 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2788 2789 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2790 2791 PetscCall(PetscCalloc1(localSize, &pblocks)); 2792 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2793 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2794 for (p = pStart; p < pEnd; ++p) { 2795 switch (dm->blocking_type) { 2796 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2797 PetscInt bdof, offset; 2798 2799 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2800 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2801 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2802 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2803 // Signal block concatenation 2804 if (dof - cdof && sectionLocal->blockStarts && !PetscBTLookup(sectionLocal->blockStarts, p)) pblocks[offset - localStart] = -(dof - cdof); 2805 dof = dof < 0 ? -(dof + 1) : dof; 2806 bdof = cdof && (dof - cdof) ? 1 : dof; 2807 if (dof) { 2808 if (bs < 0) { 2809 bs = bdof; 2810 } else if (bs != bdof) { 2811 bs = 1; 2812 } 2813 } 2814 } break; 2815 case DM_BLOCKING_FIELD_NODE: { 2816 for (PetscInt field = 0; field < num_fields; field++) { 2817 PetscInt num_comp, bdof, offset; 2818 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2819 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2820 if (dof < 0) continue; 2821 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2822 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2823 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); 2824 PetscInt num_nodes = dof / num_comp; 2825 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2826 // Handle possibly constant block size (unlikely) 2827 bdof = cdof && (dof - cdof) ? 1 : dof; 2828 if (dof) { 2829 if (bs < 0) { 2830 bs = bdof; 2831 } else if (bs != bdof) { 2832 bs = 1; 2833 } 2834 } 2835 } 2836 } break; 2837 } 2838 } 2839 /* Must have same blocksize on all procs (some might have no points) */ 2840 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2841 bsLocal[1] = bs; 2842 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2843 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2844 else bs = bsMinMax[0]; 2845 bs = PetscMax(1, bs); 2846 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2847 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2848 PetscCall(MatSetBlockSize(*J, bs)); 2849 PetscCall(MatSetUp(*J)); 2850 } else { 2851 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2852 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2853 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2854 } 2855 { // Consolidate blocks 2856 PetscInt nblocks = 0; 2857 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2858 if (pblocks[i] == 0) continue; 2859 // Negative block size indicates the blocks should be concatenated 2860 if (pblocks[i] < 0) { 2861 pblocks[i] = -pblocks[i]; 2862 pblocks[nblocks - 1] += pblocks[i]; 2863 } else { 2864 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2865 } 2866 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]); 2867 } 2868 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2869 } 2870 PetscCall(PetscFree(pblocks)); 2871 } 2872 PetscCall(MatSetDM(*J, dm)); 2873 PetscFunctionReturn(PETSC_SUCCESS); 2874 } 2875 2876 /*@ 2877 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2878 2879 Not Collective 2880 2881 Input Parameter: 2882 . dm - The `DMPLEX` 2883 2884 Output Parameter: 2885 . subsection - The subdomain section 2886 2887 Level: developer 2888 2889 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2890 @*/ 2891 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2892 { 2893 DM_Plex *mesh = (DM_Plex *)dm->data; 2894 2895 PetscFunctionBegin; 2896 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2897 if (!mesh->subdomainSection) { 2898 PetscSection section; 2899 PetscSF sf; 2900 2901 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2902 PetscCall(DMGetLocalSection(dm, §ion)); 2903 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2904 PetscCall(PetscSFDestroy(&sf)); 2905 } 2906 *subsection = mesh->subdomainSection; 2907 PetscFunctionReturn(PETSC_SUCCESS); 2908 } 2909 2910 /*@ 2911 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2912 2913 Not Collective 2914 2915 Input Parameter: 2916 . dm - The `DMPLEX` 2917 2918 Output Parameters: 2919 + pStart - The first mesh point 2920 - pEnd - The upper bound for mesh points 2921 2922 Level: beginner 2923 2924 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2925 @*/ 2926 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2927 { 2928 DM_Plex *mesh = (DM_Plex *)dm->data; 2929 2930 PetscFunctionBegin; 2931 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2932 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2933 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2934 PetscFunctionReturn(PETSC_SUCCESS); 2935 } 2936 2937 /*@ 2938 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2939 2940 Not Collective 2941 2942 Input Parameters: 2943 + dm - The `DMPLEX` 2944 . pStart - The first mesh point 2945 - pEnd - The upper bound for mesh points 2946 2947 Level: beginner 2948 2949 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2950 @*/ 2951 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2952 { 2953 DM_Plex *mesh = (DM_Plex *)dm->data; 2954 2955 PetscFunctionBegin; 2956 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2957 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2958 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2959 PetscCall(PetscFree(mesh->cellTypes)); 2960 PetscFunctionReturn(PETSC_SUCCESS); 2961 } 2962 2963 /*@ 2964 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2965 2966 Not Collective 2967 2968 Input Parameters: 2969 + dm - The `DMPLEX` 2970 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2971 2972 Output Parameter: 2973 . size - The cone size for point `p` 2974 2975 Level: beginner 2976 2977 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2978 @*/ 2979 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2980 { 2981 DM_Plex *mesh = (DM_Plex *)dm->data; 2982 2983 PetscFunctionBegin; 2984 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2985 PetscAssertPointer(size, 3); 2986 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2987 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2988 PetscFunctionReturn(PETSC_SUCCESS); 2989 } 2990 2991 /*@ 2992 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2993 2994 Not Collective 2995 2996 Input Parameters: 2997 + dm - The `DMPLEX` 2998 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2999 - size - The cone size for point `p` 3000 3001 Level: beginner 3002 3003 Note: 3004 This should be called after `DMPlexSetChart()`. 3005 3006 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3007 @*/ 3008 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3009 { 3010 DM_Plex *mesh = (DM_Plex *)dm->data; 3011 3012 PetscFunctionBegin; 3013 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3014 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3015 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3016 PetscFunctionReturn(PETSC_SUCCESS); 3017 } 3018 3019 /*@C 3020 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3021 3022 Not Collective 3023 3024 Input Parameters: 3025 + dm - The `DMPLEX` 3026 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3027 3028 Output Parameter: 3029 . cone - An array of points which are on the in-edges for point `p` 3030 3031 Level: beginner 3032 3033 Fortran Notes: 3034 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3035 `DMPlexRestoreCone()` is not needed/available in C. 3036 3037 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3038 @*/ 3039 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3040 { 3041 DM_Plex *mesh = (DM_Plex *)dm->data; 3042 PetscInt off; 3043 3044 PetscFunctionBegin; 3045 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3046 PetscAssertPointer(cone, 3); 3047 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3048 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3049 PetscFunctionReturn(PETSC_SUCCESS); 3050 } 3051 3052 /*@C 3053 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3054 3055 Not Collective 3056 3057 Input Parameters: 3058 + dm - The `DMPLEX` 3059 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3060 3061 Output Parameters: 3062 + pConesSection - `PetscSection` describing the layout of `pCones` 3063 - pCones - An array of points which are on the in-edges for the point set `p` 3064 3065 Level: intermediate 3066 3067 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3068 @*/ 3069 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3070 { 3071 PetscSection cs, newcs; 3072 PetscInt *cones; 3073 PetscInt *newarr = NULL; 3074 PetscInt n; 3075 3076 PetscFunctionBegin; 3077 PetscCall(DMPlexGetCones(dm, &cones)); 3078 PetscCall(DMPlexGetConeSection(dm, &cs)); 3079 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3080 if (pConesSection) *pConesSection = newcs; 3081 if (pCones) { 3082 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3083 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3084 } 3085 PetscFunctionReturn(PETSC_SUCCESS); 3086 } 3087 3088 /*@ 3089 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3090 3091 Not Collective 3092 3093 Input Parameters: 3094 + dm - The `DMPLEX` 3095 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3096 3097 Output Parameter: 3098 . expandedPoints - An array of vertices recursively expanded from input points 3099 3100 Level: advanced 3101 3102 Notes: 3103 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3104 3105 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3106 3107 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3108 `DMPlexGetDepth()`, `IS` 3109 @*/ 3110 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3111 { 3112 IS *expandedPointsAll; 3113 PetscInt depth; 3114 3115 PetscFunctionBegin; 3116 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3117 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3118 PetscAssertPointer(expandedPoints, 3); 3119 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3120 *expandedPoints = expandedPointsAll[0]; 3121 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3122 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3123 PetscFunctionReturn(PETSC_SUCCESS); 3124 } 3125 3126 /*@ 3127 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). 3128 3129 Not Collective 3130 3131 Input Parameters: 3132 + dm - The `DMPLEX` 3133 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3134 3135 Output Parameters: 3136 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3137 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3138 - sections - (optional) An array of sections which describe mappings from points to their cone points 3139 3140 Level: advanced 3141 3142 Notes: 3143 Like `DMPlexGetConeTuple()` but recursive. 3144 3145 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. 3146 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3147 3148 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\: 3149 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3150 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3151 3152 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3153 `DMPlexGetDepth()`, `PetscSection`, `IS` 3154 @*/ 3155 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3156 { 3157 const PetscInt *arr0 = NULL, *cone = NULL; 3158 PetscInt *arr = NULL, *newarr = NULL; 3159 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3160 IS *expandedPoints_; 3161 PetscSection *sections_; 3162 3163 PetscFunctionBegin; 3164 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3165 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3166 if (depth) PetscAssertPointer(depth, 3); 3167 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3168 if (sections) PetscAssertPointer(sections, 5); 3169 PetscCall(ISGetLocalSize(points, &n)); 3170 PetscCall(ISGetIndices(points, &arr0)); 3171 PetscCall(DMPlexGetDepth(dm, &depth_)); 3172 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3173 PetscCall(PetscCalloc1(depth_, §ions_)); 3174 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3175 for (d = depth_ - 1; d >= 0; d--) { 3176 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3177 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3178 for (i = 0; i < n; i++) { 3179 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3180 if (arr[i] >= start && arr[i] < end) { 3181 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3182 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3183 } else { 3184 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3185 } 3186 } 3187 PetscCall(PetscSectionSetUp(sections_[d])); 3188 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3189 PetscCall(PetscMalloc1(newn, &newarr)); 3190 for (i = 0; i < n; i++) { 3191 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3192 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3193 if (cn > 1) { 3194 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3195 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3196 } else { 3197 newarr[co] = arr[i]; 3198 } 3199 } 3200 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3201 arr = newarr; 3202 n = newn; 3203 } 3204 PetscCall(ISRestoreIndices(points, &arr0)); 3205 *depth = depth_; 3206 if (expandedPoints) *expandedPoints = expandedPoints_; 3207 else { 3208 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3209 PetscCall(PetscFree(expandedPoints_)); 3210 } 3211 if (sections) *sections = sections_; 3212 else { 3213 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3214 PetscCall(PetscFree(sections_)); 3215 } 3216 PetscFunctionReturn(PETSC_SUCCESS); 3217 } 3218 3219 /*@ 3220 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3221 3222 Not Collective 3223 3224 Input Parameters: 3225 + dm - The `DMPLEX` 3226 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3227 3228 Output Parameters: 3229 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3230 . expandedPoints - (optional) An array of recursively expanded cones 3231 - sections - (optional) An array of sections which describe mappings from points to their cone points 3232 3233 Level: advanced 3234 3235 Note: 3236 See `DMPlexGetConeRecursive()` 3237 3238 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3239 `DMPlexGetDepth()`, `IS`, `PetscSection` 3240 @*/ 3241 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3242 { 3243 PetscInt d, depth_; 3244 3245 PetscFunctionBegin; 3246 PetscCall(DMPlexGetDepth(dm, &depth_)); 3247 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3248 if (depth) *depth = 0; 3249 if (expandedPoints) { 3250 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3251 PetscCall(PetscFree(*expandedPoints)); 3252 } 3253 if (sections) { 3254 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3255 PetscCall(PetscFree(*sections)); 3256 } 3257 PetscFunctionReturn(PETSC_SUCCESS); 3258 } 3259 3260 /*@ 3261 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 3262 3263 Not Collective 3264 3265 Input Parameters: 3266 + dm - The `DMPLEX` 3267 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3268 - cone - An array of points which are on the in-edges for point `p` 3269 3270 Level: beginner 3271 3272 Note: 3273 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3274 3275 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3276 @*/ 3277 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3278 { 3279 DM_Plex *mesh = (DM_Plex *)dm->data; 3280 PetscInt dof, off, c; 3281 3282 PetscFunctionBegin; 3283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3284 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3285 if (dof) PetscAssertPointer(cone, 3); 3286 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3287 if (PetscDefined(USE_DEBUG)) { 3288 PetscInt pStart, pEnd; 3289 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3290 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); 3291 for (c = 0; c < dof; ++c) { 3292 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); 3293 mesh->cones[off + c] = cone[c]; 3294 } 3295 } else { 3296 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3297 } 3298 PetscFunctionReturn(PETSC_SUCCESS); 3299 } 3300 3301 /*@C 3302 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3303 3304 Not Collective 3305 3306 Input Parameters: 3307 + dm - The `DMPLEX` 3308 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3309 3310 Output Parameter: 3311 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3312 integer giving the prescription for cone traversal. 3313 3314 Level: beginner 3315 3316 Note: 3317 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3318 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3319 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3320 with the identity. 3321 3322 Fortran Notes: 3323 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3324 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3325 3326 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3327 @*/ 3328 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3329 { 3330 DM_Plex *mesh = (DM_Plex *)dm->data; 3331 PetscInt off; 3332 3333 PetscFunctionBegin; 3334 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3335 if (PetscDefined(USE_DEBUG)) { 3336 PetscInt dof; 3337 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3338 if (dof) PetscAssertPointer(coneOrientation, 3); 3339 } 3340 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3341 3342 *coneOrientation = &mesh->coneOrientations[off]; 3343 PetscFunctionReturn(PETSC_SUCCESS); 3344 } 3345 3346 /*@ 3347 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3348 3349 Not Collective 3350 3351 Input Parameters: 3352 + dm - The `DMPLEX` 3353 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3354 - coneOrientation - An array of orientations 3355 3356 Level: beginner 3357 3358 Notes: 3359 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3360 3361 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3362 3363 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3364 @*/ 3365 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3366 { 3367 DM_Plex *mesh = (DM_Plex *)dm->data; 3368 PetscInt pStart, pEnd; 3369 PetscInt dof, off, c; 3370 3371 PetscFunctionBegin; 3372 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3373 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3374 if (dof) PetscAssertPointer(coneOrientation, 3); 3375 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3376 if (PetscDefined(USE_DEBUG)) { 3377 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3378 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); 3379 for (c = 0; c < dof; ++c) { 3380 PetscInt cdof, o = coneOrientation[c]; 3381 3382 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3383 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); 3384 mesh->coneOrientations[off + c] = o; 3385 } 3386 } else { 3387 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3388 } 3389 PetscFunctionReturn(PETSC_SUCCESS); 3390 } 3391 3392 /*@ 3393 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3394 3395 Not Collective 3396 3397 Input Parameters: 3398 + dm - The `DMPLEX` 3399 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3400 . conePos - The local index in the cone where the point should be put 3401 - conePoint - The mesh point to insert 3402 3403 Level: beginner 3404 3405 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3406 @*/ 3407 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3408 { 3409 DM_Plex *mesh = (DM_Plex *)dm->data; 3410 PetscInt pStart, pEnd; 3411 PetscInt dof, off; 3412 3413 PetscFunctionBegin; 3414 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3415 if (PetscDefined(USE_DEBUG)) { 3416 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3417 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); 3418 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); 3419 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3420 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); 3421 } 3422 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3423 mesh->cones[off + conePos] = conePoint; 3424 PetscFunctionReturn(PETSC_SUCCESS); 3425 } 3426 3427 /*@ 3428 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3429 3430 Not Collective 3431 3432 Input Parameters: 3433 + dm - The `DMPLEX` 3434 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3435 . conePos - The local index in the cone where the point should be put 3436 - coneOrientation - The point orientation to insert 3437 3438 Level: beginner 3439 3440 Note: 3441 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3442 3443 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3444 @*/ 3445 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3446 { 3447 DM_Plex *mesh = (DM_Plex *)dm->data; 3448 PetscInt pStart, pEnd; 3449 PetscInt dof, off; 3450 3451 PetscFunctionBegin; 3452 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3453 if (PetscDefined(USE_DEBUG)) { 3454 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3455 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); 3456 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3457 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); 3458 } 3459 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3460 mesh->coneOrientations[off + conePos] = coneOrientation; 3461 PetscFunctionReturn(PETSC_SUCCESS); 3462 } 3463 3464 /*@C 3465 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3466 3467 Not collective 3468 3469 Input Parameters: 3470 + dm - The DMPlex 3471 - p - The point, which must lie in the chart set with DMPlexSetChart() 3472 3473 Output Parameters: 3474 + cone - An array of points which are on the in-edges for point `p` 3475 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3476 integer giving the prescription for cone traversal. 3477 3478 Level: beginner 3479 3480 Notes: 3481 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3482 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3483 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3484 with the identity. 3485 3486 Fortran Notes: 3487 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3488 `DMPlexRestoreCone()` is not needed/available in C. 3489 3490 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3491 @*/ 3492 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3493 { 3494 DM_Plex *mesh = (DM_Plex *)dm->data; 3495 3496 PetscFunctionBegin; 3497 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3498 if (mesh->tr) { 3499 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3500 } else { 3501 PetscInt off; 3502 if (PetscDefined(USE_DEBUG)) { 3503 PetscInt dof; 3504 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3505 if (dof) { 3506 if (cone) PetscAssertPointer(cone, 3); 3507 if (ornt) PetscAssertPointer(ornt, 4); 3508 } 3509 } 3510 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3511 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3512 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3513 } 3514 PetscFunctionReturn(PETSC_SUCCESS); 3515 } 3516 3517 /*@C 3518 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3519 3520 Not Collective 3521 3522 Input Parameters: 3523 + dm - The DMPlex 3524 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3525 . cone - An array of points which are on the in-edges for point p 3526 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3527 integer giving the prescription for cone traversal. 3528 3529 Level: beginner 3530 3531 Notes: 3532 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3533 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3534 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3535 with the identity. 3536 3537 Fortran Notes: 3538 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3539 `DMPlexRestoreCone()` is not needed/available in C. 3540 3541 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3542 @*/ 3543 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3544 { 3545 DM_Plex *mesh = (DM_Plex *)dm->data; 3546 3547 PetscFunctionBegin; 3548 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3549 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3550 PetscFunctionReturn(PETSC_SUCCESS); 3551 } 3552 3553 /*@ 3554 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3555 3556 Not Collective 3557 3558 Input Parameters: 3559 + dm - The `DMPLEX` 3560 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3561 3562 Output Parameter: 3563 . size - The support size for point `p` 3564 3565 Level: beginner 3566 3567 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3568 @*/ 3569 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3570 { 3571 DM_Plex *mesh = (DM_Plex *)dm->data; 3572 3573 PetscFunctionBegin; 3574 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3575 PetscAssertPointer(size, 3); 3576 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3577 PetscFunctionReturn(PETSC_SUCCESS); 3578 } 3579 3580 /*@ 3581 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3582 3583 Not Collective 3584 3585 Input Parameters: 3586 + dm - The `DMPLEX` 3587 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3588 - size - The support size for point `p` 3589 3590 Level: beginner 3591 3592 Note: 3593 This should be called after `DMPlexSetChart()`. 3594 3595 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3596 @*/ 3597 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3598 { 3599 DM_Plex *mesh = (DM_Plex *)dm->data; 3600 3601 PetscFunctionBegin; 3602 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3603 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3604 PetscFunctionReturn(PETSC_SUCCESS); 3605 } 3606 3607 /*@C 3608 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3609 3610 Not Collective 3611 3612 Input Parameters: 3613 + dm - The `DMPLEX` 3614 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3615 3616 Output Parameter: 3617 . support - An array of points which are on the out-edges for point `p` 3618 3619 Level: beginner 3620 3621 Fortran Notes: 3622 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3623 `DMPlexRestoreSupport()` is not needed/available in C. 3624 3625 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3626 @*/ 3627 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3628 { 3629 DM_Plex *mesh = (DM_Plex *)dm->data; 3630 PetscInt off; 3631 3632 PetscFunctionBegin; 3633 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3634 PetscAssertPointer(support, 3); 3635 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3636 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3637 PetscFunctionReturn(PETSC_SUCCESS); 3638 } 3639 3640 /*@ 3641 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3642 3643 Not Collective 3644 3645 Input Parameters: 3646 + dm - The `DMPLEX` 3647 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3648 - support - An array of points which are on the out-edges for point `p` 3649 3650 Level: beginner 3651 3652 Note: 3653 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3654 3655 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3656 @*/ 3657 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3658 { 3659 DM_Plex *mesh = (DM_Plex *)dm->data; 3660 PetscInt pStart, pEnd; 3661 PetscInt dof, off, c; 3662 3663 PetscFunctionBegin; 3664 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3665 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3666 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3667 if (dof) PetscAssertPointer(support, 3); 3668 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3669 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); 3670 for (c = 0; c < dof; ++c) { 3671 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); 3672 mesh->supports[off + c] = support[c]; 3673 } 3674 PetscFunctionReturn(PETSC_SUCCESS); 3675 } 3676 3677 /*@ 3678 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3679 3680 Not Collective 3681 3682 Input Parameters: 3683 + dm - The `DMPLEX` 3684 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3685 . supportPos - The local index in the cone where the point should be put 3686 - supportPoint - The mesh point to insert 3687 3688 Level: beginner 3689 3690 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3691 @*/ 3692 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3693 { 3694 DM_Plex *mesh = (DM_Plex *)dm->data; 3695 PetscInt pStart, pEnd; 3696 PetscInt dof, off; 3697 3698 PetscFunctionBegin; 3699 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3700 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3701 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3702 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3703 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); 3704 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); 3705 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); 3706 mesh->supports[off + supportPos] = supportPoint; 3707 PetscFunctionReturn(PETSC_SUCCESS); 3708 } 3709 3710 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3711 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3712 { 3713 switch (ct) { 3714 case DM_POLYTOPE_SEGMENT: 3715 if (o == -1) return -2; 3716 break; 3717 case DM_POLYTOPE_TRIANGLE: 3718 if (o == -3) return -1; 3719 if (o == -2) return -3; 3720 if (o == -1) return -2; 3721 break; 3722 case DM_POLYTOPE_QUADRILATERAL: 3723 if (o == -4) return -2; 3724 if (o == -3) return -1; 3725 if (o == -2) return -4; 3726 if (o == -1) return -3; 3727 break; 3728 default: 3729 return o; 3730 } 3731 return o; 3732 } 3733 3734 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3735 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3736 { 3737 switch (ct) { 3738 case DM_POLYTOPE_SEGMENT: 3739 if ((o == -2) || (o == 1)) return -1; 3740 if (o == -1) return 0; 3741 break; 3742 case DM_POLYTOPE_TRIANGLE: 3743 if (o == -3) return -2; 3744 if (o == -2) return -1; 3745 if (o == -1) return -3; 3746 break; 3747 case DM_POLYTOPE_QUADRILATERAL: 3748 if (o == -4) return -2; 3749 if (o == -3) return -1; 3750 if (o == -2) return -4; 3751 if (o == -1) return -3; 3752 break; 3753 default: 3754 return o; 3755 } 3756 return o; 3757 } 3758 3759 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3760 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3761 { 3762 PetscInt pStart, pEnd, p; 3763 3764 PetscFunctionBegin; 3765 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3766 for (p = pStart; p < pEnd; ++p) { 3767 const PetscInt *cone, *ornt; 3768 PetscInt coneSize, c; 3769 3770 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3771 PetscCall(DMPlexGetCone(dm, p, &cone)); 3772 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3773 for (c = 0; c < coneSize; ++c) { 3774 DMPolytopeType ct; 3775 const PetscInt o = ornt[c]; 3776 3777 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3778 switch (ct) { 3779 case DM_POLYTOPE_SEGMENT: 3780 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3781 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3782 break; 3783 case DM_POLYTOPE_TRIANGLE: 3784 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3785 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3786 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3787 break; 3788 case DM_POLYTOPE_QUADRILATERAL: 3789 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3790 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3791 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3792 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3793 break; 3794 default: 3795 break; 3796 } 3797 } 3798 } 3799 PetscFunctionReturn(PETSC_SUCCESS); 3800 } 3801 3802 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3803 { 3804 DM_Plex *mesh = (DM_Plex *)dm->data; 3805 3806 PetscFunctionBeginHot; 3807 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3808 if (useCone) { 3809 PetscCall(DMPlexGetConeSize(dm, p, size)); 3810 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3811 } else { 3812 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3813 PetscCall(DMPlexGetSupport(dm, p, arr)); 3814 } 3815 } else { 3816 if (useCone) { 3817 const PetscSection s = mesh->coneSection; 3818 const PetscInt ps = p - s->pStart; 3819 const PetscInt off = s->atlasOff[ps]; 3820 3821 *size = s->atlasDof[ps]; 3822 *arr = mesh->cones + off; 3823 *ornt = mesh->coneOrientations + off; 3824 } else { 3825 const PetscSection s = mesh->supportSection; 3826 const PetscInt ps = p - s->pStart; 3827 const PetscInt off = s->atlasOff[ps]; 3828 3829 *size = s->atlasDof[ps]; 3830 *arr = mesh->supports + off; 3831 } 3832 } 3833 PetscFunctionReturn(PETSC_SUCCESS); 3834 } 3835 3836 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3837 { 3838 DM_Plex *mesh = (DM_Plex *)dm->data; 3839 3840 PetscFunctionBeginHot; 3841 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3842 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3843 } 3844 PetscFunctionReturn(PETSC_SUCCESS); 3845 } 3846 3847 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3848 { 3849 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3850 PetscInt *closure; 3851 const PetscInt *tmp = NULL, *tmpO = NULL; 3852 PetscInt off = 0, tmpSize, t; 3853 3854 PetscFunctionBeginHot; 3855 if (ornt) { 3856 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3857 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; 3858 } 3859 if (*points) { 3860 closure = *points; 3861 } else { 3862 PetscInt maxConeSize, maxSupportSize; 3863 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3864 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3865 } 3866 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3867 if (ct == DM_POLYTOPE_UNKNOWN) { 3868 closure[off++] = p; 3869 closure[off++] = 0; 3870 for (t = 0; t < tmpSize; ++t) { 3871 closure[off++] = tmp[t]; 3872 closure[off++] = tmpO ? tmpO[t] : 0; 3873 } 3874 } else { 3875 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3876 3877 /* We assume that cells with a valid type have faces with a valid type */ 3878 closure[off++] = p; 3879 closure[off++] = ornt; 3880 for (t = 0; t < tmpSize; ++t) { 3881 DMPolytopeType ft; 3882 3883 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3884 closure[off++] = tmp[arr[t]]; 3885 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3886 } 3887 } 3888 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3889 if (numPoints) *numPoints = tmpSize + 1; 3890 if (points) *points = closure; 3891 PetscFunctionReturn(PETSC_SUCCESS); 3892 } 3893 3894 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3895 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3896 { 3897 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3898 const PetscInt *cone, *ornt; 3899 PetscInt *pts, *closure = NULL; 3900 DMPolytopeType ft; 3901 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3902 PetscInt dim, coneSize, c, d, clSize, cl; 3903 3904 PetscFunctionBeginHot; 3905 PetscCall(DMGetDimension(dm, &dim)); 3906 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3907 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3908 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3909 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3910 maxSize = PetscMax(coneSeries, supportSeries); 3911 if (*points) { 3912 pts = *points; 3913 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3914 c = 0; 3915 pts[c++] = point; 3916 pts[c++] = o; 3917 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3918 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3919 for (cl = 0; cl < clSize * 2; cl += 2) { 3920 pts[c++] = closure[cl]; 3921 pts[c++] = closure[cl + 1]; 3922 } 3923 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3924 for (cl = 0; cl < clSize * 2; cl += 2) { 3925 pts[c++] = closure[cl]; 3926 pts[c++] = closure[cl + 1]; 3927 } 3928 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3929 for (d = 2; d < coneSize; ++d) { 3930 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3931 pts[c++] = cone[arr[d * 2 + 0]]; 3932 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3933 } 3934 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3935 if (dim >= 3) { 3936 for (d = 2; d < coneSize; ++d) { 3937 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3938 const PetscInt *fcone, *fornt; 3939 PetscInt fconeSize, fc, i; 3940 3941 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3942 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3943 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3944 for (fc = 0; fc < fconeSize; ++fc) { 3945 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3946 const PetscInt co = farr[fc * 2 + 1]; 3947 3948 for (i = 0; i < c; i += 2) 3949 if (pts[i] == cp) break; 3950 if (i == c) { 3951 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3952 pts[c++] = cp; 3953 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3954 } 3955 } 3956 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3957 } 3958 } 3959 *numPoints = c / 2; 3960 *points = pts; 3961 PetscFunctionReturn(PETSC_SUCCESS); 3962 } 3963 3964 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3965 { 3966 DMPolytopeType ct; 3967 PetscInt *closure, *fifo; 3968 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3969 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3970 PetscInt depth, maxSize; 3971 3972 PetscFunctionBeginHot; 3973 PetscCall(DMPlexGetDepth(dm, &depth)); 3974 if (depth == 1) { 3975 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3976 PetscFunctionReturn(PETSC_SUCCESS); 3977 } 3978 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3979 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; 3980 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 3981 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3982 PetscFunctionReturn(PETSC_SUCCESS); 3983 } 3984 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3985 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3986 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3987 maxSize = PetscMax(coneSeries, supportSeries); 3988 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3989 if (*points) { 3990 closure = *points; 3991 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3992 closure[closureSize++] = p; 3993 closure[closureSize++] = ornt; 3994 fifo[fifoSize++] = p; 3995 fifo[fifoSize++] = ornt; 3996 fifo[fifoSize++] = ct; 3997 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3998 while (fifoSize - fifoStart) { 3999 const PetscInt q = fifo[fifoStart++]; 4000 const PetscInt o = fifo[fifoStart++]; 4001 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4002 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4003 const PetscInt *tmp, *tmpO = NULL; 4004 PetscInt tmpSize, t; 4005 4006 if (PetscDefined(USE_DEBUG)) { 4007 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4008 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); 4009 } 4010 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4011 for (t = 0; t < tmpSize; ++t) { 4012 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4013 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4014 const PetscInt cp = tmp[ip]; 4015 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4016 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4017 PetscInt c; 4018 4019 /* Check for duplicate */ 4020 for (c = 0; c < closureSize; c += 2) { 4021 if (closure[c] == cp) break; 4022 } 4023 if (c == closureSize) { 4024 closure[closureSize++] = cp; 4025 closure[closureSize++] = co; 4026 fifo[fifoSize++] = cp; 4027 fifo[fifoSize++] = co; 4028 fifo[fifoSize++] = ct; 4029 } 4030 } 4031 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4032 } 4033 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4034 if (numPoints) *numPoints = closureSize / 2; 4035 if (points) *points = closure; 4036 PetscFunctionReturn(PETSC_SUCCESS); 4037 } 4038 4039 /*@C 4040 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4041 4042 Not Collective 4043 4044 Input Parameters: 4045 + dm - The `DMPLEX` 4046 . p - The mesh point 4047 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4048 4049 Input/Output Parameter: 4050 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4051 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4052 4053 Output Parameter: 4054 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4055 4056 Level: beginner 4057 4058 Note: 4059 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4060 4061 Fortran Notes: 4062 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4063 4064 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4065 @*/ 4066 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4067 { 4068 PetscFunctionBeginHot; 4069 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4070 if (numPoints) PetscAssertPointer(numPoints, 4); 4071 if (points) PetscAssertPointer(points, 5); 4072 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4073 PetscFunctionReturn(PETSC_SUCCESS); 4074 } 4075 4076 /*@C 4077 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4078 4079 Not Collective 4080 4081 Input Parameters: 4082 + dm - The `DMPLEX` 4083 . p - The mesh point 4084 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4085 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4086 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4087 4088 Level: beginner 4089 4090 Note: 4091 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4092 4093 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4094 @*/ 4095 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4096 { 4097 PetscFunctionBeginHot; 4098 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4099 if (numPoints) *numPoints = 0; 4100 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4101 PetscFunctionReturn(PETSC_SUCCESS); 4102 } 4103 4104 /*@ 4105 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4106 4107 Not Collective 4108 4109 Input Parameter: 4110 . dm - The `DMPLEX` 4111 4112 Output Parameters: 4113 + maxConeSize - The maximum number of in-edges 4114 - maxSupportSize - The maximum number of out-edges 4115 4116 Level: beginner 4117 4118 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4119 @*/ 4120 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4121 { 4122 DM_Plex *mesh = (DM_Plex *)dm->data; 4123 4124 PetscFunctionBegin; 4125 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4126 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4127 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4128 PetscFunctionReturn(PETSC_SUCCESS); 4129 } 4130 4131 PetscErrorCode DMSetUp_Plex(DM dm) 4132 { 4133 DM_Plex *mesh = (DM_Plex *)dm->data; 4134 PetscInt size, maxSupportSize; 4135 4136 PetscFunctionBegin; 4137 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4138 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4139 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4140 PetscCall(PetscMalloc1(size, &mesh->cones)); 4141 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4142 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4143 if (maxSupportSize) { 4144 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4145 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4146 PetscCall(PetscMalloc1(size, &mesh->supports)); 4147 } 4148 PetscFunctionReturn(PETSC_SUCCESS); 4149 } 4150 4151 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4152 { 4153 PetscFunctionBegin; 4154 if (subdm) PetscCall(DMClone(dm, subdm)); 4155 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 4156 if (subdm) (*subdm)->useNatural = dm->useNatural; 4157 if (dm->useNatural && dm->sfMigration) { 4158 PetscSF sfNatural; 4159 4160 (*subdm)->sfMigration = dm->sfMigration; 4161 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4162 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4163 (*subdm)->sfNatural = sfNatural; 4164 } 4165 PetscFunctionReturn(PETSC_SUCCESS); 4166 } 4167 4168 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4169 { 4170 PetscInt i = 0; 4171 4172 PetscFunctionBegin; 4173 PetscCall(DMClone(dms[0], superdm)); 4174 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4175 (*superdm)->useNatural = PETSC_FALSE; 4176 for (i = 0; i < len; i++) { 4177 if (dms[i]->useNatural && dms[i]->sfMigration) { 4178 PetscSF sfNatural; 4179 4180 (*superdm)->sfMigration = dms[i]->sfMigration; 4181 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4182 (*superdm)->useNatural = PETSC_TRUE; 4183 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4184 (*superdm)->sfNatural = sfNatural; 4185 break; 4186 } 4187 } 4188 PetscFunctionReturn(PETSC_SUCCESS); 4189 } 4190 4191 /*@ 4192 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4193 4194 Not Collective 4195 4196 Input Parameter: 4197 . dm - The `DMPLEX` 4198 4199 Level: beginner 4200 4201 Note: 4202 This should be called after all calls to `DMPlexSetCone()` 4203 4204 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4205 @*/ 4206 PetscErrorCode DMPlexSymmetrize(DM dm) 4207 { 4208 DM_Plex *mesh = (DM_Plex *)dm->data; 4209 PetscInt *offsets; 4210 PetscInt supportSize; 4211 PetscInt pStart, pEnd, p; 4212 4213 PetscFunctionBegin; 4214 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4215 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4216 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4217 /* Calculate support sizes */ 4218 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4219 for (p = pStart; p < pEnd; ++p) { 4220 PetscInt dof, off, c; 4221 4222 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4223 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4224 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4225 } 4226 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4227 /* Calculate supports */ 4228 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4229 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4230 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4231 for (p = pStart; p < pEnd; ++p) { 4232 PetscInt dof, off, c; 4233 4234 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4235 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4236 for (c = off; c < off + dof; ++c) { 4237 const PetscInt q = mesh->cones[c]; 4238 PetscInt offS; 4239 4240 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4241 4242 mesh->supports[offS + offsets[q]] = p; 4243 ++offsets[q]; 4244 } 4245 } 4246 PetscCall(PetscFree(offsets)); 4247 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4248 PetscFunctionReturn(PETSC_SUCCESS); 4249 } 4250 4251 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4252 { 4253 IS stratumIS; 4254 4255 PetscFunctionBegin; 4256 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4257 if (PetscDefined(USE_DEBUG)) { 4258 PetscInt qStart, qEnd, numLevels, level; 4259 PetscBool overlap = PETSC_FALSE; 4260 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4261 for (level = 0; level < numLevels; level++) { 4262 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4263 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4264 overlap = PETSC_TRUE; 4265 break; 4266 } 4267 } 4268 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); 4269 } 4270 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4271 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4272 PetscCall(ISDestroy(&stratumIS)); 4273 PetscFunctionReturn(PETSC_SUCCESS); 4274 } 4275 4276 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4277 { 4278 PetscInt *pMin, *pMax; 4279 PetscInt pStart, pEnd; 4280 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4281 4282 PetscFunctionBegin; 4283 { 4284 DMLabel label2; 4285 4286 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4287 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4288 } 4289 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4290 for (PetscInt p = pStart; p < pEnd; ++p) { 4291 DMPolytopeType ct; 4292 4293 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4294 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4295 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4296 } 4297 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4298 for (PetscInt d = dmin; d <= dmax; ++d) { 4299 pMin[d] = PETSC_MAX_INT; 4300 pMax[d] = PETSC_MIN_INT; 4301 } 4302 for (PetscInt p = pStart; p < pEnd; ++p) { 4303 DMPolytopeType ct; 4304 PetscInt d; 4305 4306 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4307 d = DMPolytopeTypeGetDim(ct); 4308 pMin[d] = PetscMin(p, pMin[d]); 4309 pMax[d] = PetscMax(p, pMax[d]); 4310 } 4311 for (PetscInt d = dmin; d <= dmax; ++d) { 4312 if (pMin[d] > pMax[d]) continue; 4313 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4314 } 4315 PetscCall(PetscFree2(pMin, pMax)); 4316 PetscFunctionReturn(PETSC_SUCCESS); 4317 } 4318 4319 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4320 { 4321 PetscInt pStart, pEnd; 4322 PetscInt numRoots = 0, numLeaves = 0; 4323 4324 PetscFunctionBegin; 4325 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4326 { 4327 /* Initialize roots and count leaves */ 4328 PetscInt sMin = PETSC_MAX_INT; 4329 PetscInt sMax = PETSC_MIN_INT; 4330 PetscInt coneSize, supportSize; 4331 4332 for (PetscInt p = pStart; p < pEnd; ++p) { 4333 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4334 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4335 if (!coneSize && supportSize) { 4336 sMin = PetscMin(p, sMin); 4337 sMax = PetscMax(p, sMax); 4338 ++numRoots; 4339 } else if (!supportSize && coneSize) { 4340 ++numLeaves; 4341 } else if (!supportSize && !coneSize) { 4342 /* Isolated points */ 4343 sMin = PetscMin(p, sMin); 4344 sMax = PetscMax(p, sMax); 4345 } 4346 } 4347 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4348 } 4349 4350 if (numRoots + numLeaves == (pEnd - pStart)) { 4351 PetscInt sMin = PETSC_MAX_INT; 4352 PetscInt sMax = PETSC_MIN_INT; 4353 PetscInt coneSize, supportSize; 4354 4355 for (PetscInt p = pStart; p < pEnd; ++p) { 4356 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4357 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4358 if (!supportSize && coneSize) { 4359 sMin = PetscMin(p, sMin); 4360 sMax = PetscMax(p, sMax); 4361 } 4362 } 4363 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4364 } else { 4365 PetscInt level = 0; 4366 PetscInt qStart, qEnd; 4367 4368 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4369 while (qEnd > qStart) { 4370 PetscInt sMin = PETSC_MAX_INT; 4371 PetscInt sMax = PETSC_MIN_INT; 4372 4373 for (PetscInt q = qStart; q < qEnd; ++q) { 4374 const PetscInt *support; 4375 PetscInt supportSize; 4376 4377 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4378 PetscCall(DMPlexGetSupport(dm, q, &support)); 4379 for (PetscInt s = 0; s < supportSize; ++s) { 4380 sMin = PetscMin(support[s], sMin); 4381 sMax = PetscMax(support[s], sMax); 4382 } 4383 } 4384 PetscCall(DMLabelGetNumValues(label, &level)); 4385 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4386 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4387 } 4388 } 4389 PetscFunctionReturn(PETSC_SUCCESS); 4390 } 4391 4392 /*@ 4393 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4394 4395 Collective 4396 4397 Input Parameter: 4398 . dm - The `DMPLEX` 4399 4400 Level: beginner 4401 4402 Notes: 4403 The strata group all points of the same grade, and this function calculates the strata. This 4404 grade can be seen as the height (or depth) of the point in the DAG. 4405 4406 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4407 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4408 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4409 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4410 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4411 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4412 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4413 4414 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4415 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4416 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 4417 to interpolate only that one (e0), so that 4418 .vb 4419 cone(c0) = {e0, v2} 4420 cone(e0) = {v0, v1} 4421 .ve 4422 If `DMPlexStratify()` is run on this mesh, it will give depths 4423 .vb 4424 depth 0 = {v0, v1, v2} 4425 depth 1 = {e0, c0} 4426 .ve 4427 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4428 4429 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4430 4431 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4432 @*/ 4433 PetscErrorCode DMPlexStratify(DM dm) 4434 { 4435 DM_Plex *mesh = (DM_Plex *)dm->data; 4436 DMLabel label; 4437 PetscBool flg = PETSC_FALSE; 4438 4439 PetscFunctionBegin; 4440 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4441 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4442 4443 // Create depth label 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, s; 5529 Mat m; 5530 PetscInt maxHeight; 5531 const char *prefix; 5532 5533 PetscFunctionBegin; 5534 PetscCall(DMClone(dm, cdm)); 5535 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5536 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5537 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5538 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5539 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5540 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5541 PetscCall(DMSetLocalSection(*cdm, section)); 5542 PetscCall(PetscSectionDestroy(§ion)); 5543 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5544 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5545 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5546 PetscCall(PetscSectionDestroy(&s)); 5547 PetscCall(MatDestroy(&m)); 5548 5549 PetscCall(DMSetNumFields(*cdm, 1)); 5550 PetscCall(DMCreateDS(*cdm)); 5551 (*cdm)->cloneOpts = PETSC_TRUE; 5552 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5553 PetscFunctionReturn(PETSC_SUCCESS); 5554 } 5555 5556 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5557 { 5558 Vec coordsLocal, cellCoordsLocal; 5559 DM coordsDM, cellCoordsDM; 5560 5561 PetscFunctionBegin; 5562 *field = NULL; 5563 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5564 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5565 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5566 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5567 if (coordsLocal && coordsDM) { 5568 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5569 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5570 } 5571 PetscFunctionReturn(PETSC_SUCCESS); 5572 } 5573 5574 /*@C 5575 DMPlexGetConeSection - Return a section which describes the layout of cone data 5576 5577 Not Collective 5578 5579 Input Parameter: 5580 . dm - The `DMPLEX` object 5581 5582 Output Parameter: 5583 . section - The `PetscSection` object 5584 5585 Level: developer 5586 5587 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5588 @*/ 5589 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5590 { 5591 DM_Plex *mesh = (DM_Plex *)dm->data; 5592 5593 PetscFunctionBegin; 5594 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5595 if (section) *section = mesh->coneSection; 5596 PetscFunctionReturn(PETSC_SUCCESS); 5597 } 5598 5599 /*@C 5600 DMPlexGetSupportSection - Return a section which describes the layout of support data 5601 5602 Not Collective 5603 5604 Input Parameter: 5605 . dm - The `DMPLEX` object 5606 5607 Output Parameter: 5608 . section - The `PetscSection` object 5609 5610 Level: developer 5611 5612 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5613 @*/ 5614 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5615 { 5616 DM_Plex *mesh = (DM_Plex *)dm->data; 5617 5618 PetscFunctionBegin; 5619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5620 if (section) *section = mesh->supportSection; 5621 PetscFunctionReturn(PETSC_SUCCESS); 5622 } 5623 5624 /*@C 5625 DMPlexGetCones - Return cone data 5626 5627 Not Collective 5628 5629 Input Parameter: 5630 . dm - The `DMPLEX` object 5631 5632 Output Parameter: 5633 . cones - The cone for each point 5634 5635 Level: developer 5636 5637 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5638 @*/ 5639 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5640 { 5641 DM_Plex *mesh = (DM_Plex *)dm->data; 5642 5643 PetscFunctionBegin; 5644 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5645 if (cones) *cones = mesh->cones; 5646 PetscFunctionReturn(PETSC_SUCCESS); 5647 } 5648 5649 /*@C 5650 DMPlexGetConeOrientations - Return cone orientation data 5651 5652 Not Collective 5653 5654 Input Parameter: 5655 . dm - The `DMPLEX` object 5656 5657 Output Parameter: 5658 . coneOrientations - The array of cone orientations for all points 5659 5660 Level: developer 5661 5662 Notes: 5663 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5664 5665 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5666 5667 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5668 @*/ 5669 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5670 { 5671 DM_Plex *mesh = (DM_Plex *)dm->data; 5672 5673 PetscFunctionBegin; 5674 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5675 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5676 PetscFunctionReturn(PETSC_SUCCESS); 5677 } 5678 5679 /******************************** FEM Support **********************************/ 5680 5681 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5682 { 5683 PetscInt depth; 5684 5685 PetscFunctionBegin; 5686 PetscCall(DMPlexGetDepth(plex, &depth)); 5687 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5688 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5689 PetscFunctionReturn(PETSC_SUCCESS); 5690 } 5691 5692 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5693 { 5694 PetscInt depth; 5695 5696 PetscFunctionBegin; 5697 PetscCall(DMPlexGetDepth(plex, &depth)); 5698 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5699 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5700 PetscFunctionReturn(PETSC_SUCCESS); 5701 } 5702 5703 /* 5704 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5705 representing a line in the section. 5706 */ 5707 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5708 { 5709 PetscObject obj; 5710 PetscClassId id; 5711 PetscFE fe = NULL; 5712 5713 PetscFunctionBeginHot; 5714 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5715 PetscCall(DMGetField(dm, field, NULL, &obj)); 5716 PetscCall(PetscObjectGetClassId(obj, &id)); 5717 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5718 5719 if (!fe) { 5720 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5721 /* An order k SEM disc has k-1 dofs on an edge */ 5722 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5723 *k = *k / *Nc + 1; 5724 } else { 5725 PetscInt dual_space_size, dim; 5726 PetscDualSpace dsp; 5727 5728 PetscCall(DMGetDimension(dm, &dim)); 5729 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5730 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5731 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5732 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5733 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5734 } 5735 PetscFunctionReturn(PETSC_SUCCESS); 5736 } 5737 5738 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5739 { 5740 PetscFunctionBeginHot; 5741 if (tensor) { 5742 *dof = PetscPowInt(k + 1, dim); 5743 } else { 5744 switch (dim) { 5745 case 1: 5746 *dof = k + 1; 5747 break; 5748 case 2: 5749 *dof = ((k + 1) * (k + 2)) / 2; 5750 break; 5751 case 3: 5752 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5753 break; 5754 default: 5755 *dof = 0; 5756 } 5757 } 5758 PetscFunctionReturn(PETSC_SUCCESS); 5759 } 5760 5761 /*@ 5762 5763 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5764 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5765 section provided (or the section of the `DM`). 5766 5767 Input Parameters: 5768 + dm - The `DM` 5769 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5770 - section - The `PetscSection` to reorder, or `NULL` for the default section 5771 5772 Example: 5773 A typical interpolated single-quad mesh might order points as 5774 .vb 5775 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5776 5777 v4 -- e6 -- v3 5778 | | 5779 e7 c0 e8 5780 | | 5781 v1 -- e5 -- v2 5782 .ve 5783 5784 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5785 dofs in the order of points, e.g., 5786 .vb 5787 c0 -> [0,1,2,3] 5788 v1 -> [4] 5789 ... 5790 e5 -> [8, 9] 5791 .ve 5792 5793 which corresponds to the dofs 5794 .vb 5795 6 10 11 7 5796 13 2 3 15 5797 12 0 1 14 5798 4 8 9 5 5799 .ve 5800 5801 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5802 .vb 5803 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5804 .ve 5805 5806 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5807 .vb 5808 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5809 .ve 5810 5811 Level: developer 5812 5813 Notes: 5814 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5815 degree of the basis. 5816 5817 This is required to run with libCEED. 5818 5819 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5820 @*/ 5821 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5822 { 5823 DMLabel label; 5824 PetscInt dim, depth = -1, eStart = -1, Nf; 5825 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5826 5827 PetscFunctionBegin; 5828 PetscCall(DMGetDimension(dm, &dim)); 5829 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5830 if (point < 0) { 5831 PetscInt sStart, sEnd; 5832 5833 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5834 point = sEnd - sStart ? sStart : point; 5835 } 5836 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5837 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5838 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5839 if (depth == 1) { 5840 eStart = point; 5841 } else if (depth == dim) { 5842 const PetscInt *cone; 5843 5844 PetscCall(DMPlexGetCone(dm, point, &cone)); 5845 if (dim == 2) eStart = cone[0]; 5846 else if (dim == 3) { 5847 const PetscInt *cone2; 5848 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5849 eStart = cone2[0]; 5850 } 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); 5851 } 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); 5852 5853 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5854 for (PetscInt d = 1; d <= dim; d++) { 5855 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5856 PetscInt *perm; 5857 5858 for (f = 0; f < Nf; ++f) { 5859 PetscInt dof; 5860 5861 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5862 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5863 if (!continuous && d < dim) continue; 5864 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5865 size += dof * Nc; 5866 } 5867 PetscCall(PetscMalloc1(size, &perm)); 5868 for (f = 0; f < Nf; ++f) { 5869 switch (d) { 5870 case 1: 5871 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5872 if (!continuous && d < dim) continue; 5873 /* 5874 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5875 We want [ vtx0; edge of length k-1; vtx1 ] 5876 */ 5877 if (continuous) { 5878 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5879 for (i = 0; i < k - 1; i++) 5880 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5881 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5882 foffset = offset; 5883 } else { 5884 PetscInt dof; 5885 5886 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5887 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5888 foffset = offset; 5889 } 5890 break; 5891 case 2: 5892 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5893 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5894 if (!continuous && d < dim) continue; 5895 /* The SEM order is 5896 5897 v_lb, {e_b}, v_rb, 5898 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5899 v_lt, reverse {e_t}, v_rt 5900 */ 5901 if (continuous) { 5902 const PetscInt of = 0; 5903 const PetscInt oeb = of + PetscSqr(k - 1); 5904 const PetscInt oer = oeb + (k - 1); 5905 const PetscInt oet = oer + (k - 1); 5906 const PetscInt oel = oet + (k - 1); 5907 const PetscInt ovlb = oel + (k - 1); 5908 const PetscInt ovrb = ovlb + 1; 5909 const PetscInt ovrt = ovrb + 1; 5910 const PetscInt ovlt = ovrt + 1; 5911 PetscInt o; 5912 5913 /* bottom */ 5914 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5915 for (o = oeb; o < oer; ++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] = ovrb * Nc + c + foffset; 5918 /* middle */ 5919 for (i = 0; i < k - 1; ++i) { 5920 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5921 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++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] = (oer + i) * Nc + c + foffset; 5924 } 5925 /* top */ 5926 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5927 for (o = oel - 1; o >= oet; --o) 5928 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5929 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5930 foffset = offset; 5931 } else { 5932 PetscInt dof; 5933 5934 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5935 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5936 foffset = offset; 5937 } 5938 break; 5939 case 3: 5940 /* The original hex closure is 5941 5942 {c, 5943 f_b, f_t, f_f, f_b, f_r, f_l, 5944 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5945 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5946 */ 5947 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5948 if (!continuous && d < dim) continue; 5949 /* The SEM order is 5950 Bottom Slice 5951 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5952 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5953 v_blb, {e_bb}, v_brb, 5954 5955 Middle Slice (j) 5956 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5957 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5958 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5959 5960 Top Slice 5961 v_tlf, {e_tf}, v_trf, 5962 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5963 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5964 */ 5965 if (continuous) { 5966 const PetscInt oc = 0; 5967 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5968 const PetscInt oft = ofb + PetscSqr(k - 1); 5969 const PetscInt off = oft + PetscSqr(k - 1); 5970 const PetscInt ofk = off + PetscSqr(k - 1); 5971 const PetscInt ofr = ofk + PetscSqr(k - 1); 5972 const PetscInt ofl = ofr + PetscSqr(k - 1); 5973 const PetscInt oebl = ofl + PetscSqr(k - 1); 5974 const PetscInt oebb = oebl + (k - 1); 5975 const PetscInt oebr = oebb + (k - 1); 5976 const PetscInt oebf = oebr + (k - 1); 5977 const PetscInt oetf = oebf + (k - 1); 5978 const PetscInt oetr = oetf + (k - 1); 5979 const PetscInt oetb = oetr + (k - 1); 5980 const PetscInt oetl = oetb + (k - 1); 5981 const PetscInt oerf = oetl + (k - 1); 5982 const PetscInt oelf = oerf + (k - 1); 5983 const PetscInt oelb = oelf + (k - 1); 5984 const PetscInt oerb = oelb + (k - 1); 5985 const PetscInt ovblf = oerb + (k - 1); 5986 const PetscInt ovblb = ovblf + 1; 5987 const PetscInt ovbrb = ovblb + 1; 5988 const PetscInt ovbrf = ovbrb + 1; 5989 const PetscInt ovtlf = ovbrf + 1; 5990 const PetscInt ovtrf = ovtlf + 1; 5991 const PetscInt ovtrb = ovtrf + 1; 5992 const PetscInt ovtlb = ovtrb + 1; 5993 PetscInt o, n; 5994 5995 /* Bottom Slice */ 5996 /* bottom */ 5997 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5998 for (o = oetf - 1; o >= oebf; --o) 5999 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6000 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6001 /* middle */ 6002 for (i = 0; i < k - 1; ++i) { 6003 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6004 for (n = 0; n < k - 1; ++n) { 6005 o = ofb + n * (k - 1) + i; 6006 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6007 } 6008 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6009 } 6010 /* top */ 6011 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6012 for (o = oebb; o < oebr; ++o) 6013 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6014 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6015 6016 /* Middle Slice */ 6017 for (j = 0; j < k - 1; ++j) { 6018 /* bottom */ 6019 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6020 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6021 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6022 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6023 /* middle */ 6024 for (i = 0; i < k - 1; ++i) { 6025 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6026 for (n = 0; n < k - 1; ++n) 6027 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6028 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6029 } 6030 /* top */ 6031 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6032 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6033 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6034 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6035 } 6036 6037 /* Top Slice */ 6038 /* bottom */ 6039 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6040 for (o = oetf; o < oetr; ++o) 6041 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6042 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6043 /* middle */ 6044 for (i = 0; i < k - 1; ++i) { 6045 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6046 for (n = 0; n < k - 1; ++n) 6047 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6048 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6049 } 6050 /* top */ 6051 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6052 for (o = oetl - 1; o >= oetb; --o) 6053 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6054 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6055 6056 foffset = offset; 6057 } else { 6058 PetscInt dof; 6059 6060 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6061 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6062 foffset = offset; 6063 } 6064 break; 6065 default: 6066 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6067 } 6068 } 6069 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6070 /* Check permutation */ 6071 { 6072 PetscInt *check; 6073 6074 PetscCall(PetscMalloc1(size, &check)); 6075 for (i = 0; i < size; ++i) { 6076 check[i] = -1; 6077 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6078 } 6079 for (i = 0; i < size; ++i) check[perm[i]] = i; 6080 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6081 PetscCall(PetscFree(check)); 6082 } 6083 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6084 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6085 PetscInt *loc_perm; 6086 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6087 for (PetscInt i = 0; i < size; i++) { 6088 loc_perm[i] = perm[i]; 6089 loc_perm[size + i] = size + perm[i]; 6090 } 6091 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6092 } 6093 } 6094 PetscFunctionReturn(PETSC_SUCCESS); 6095 } 6096 6097 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6098 { 6099 PetscDS prob; 6100 PetscInt depth, Nf, h; 6101 DMLabel label; 6102 6103 PetscFunctionBeginHot; 6104 PetscCall(DMGetDS(dm, &prob)); 6105 Nf = prob->Nf; 6106 label = dm->depthLabel; 6107 *dspace = NULL; 6108 if (field < Nf) { 6109 PetscObject disc = prob->disc[field]; 6110 6111 if (disc->classid == PETSCFE_CLASSID) { 6112 PetscDualSpace dsp; 6113 6114 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6115 PetscCall(DMLabelGetNumValues(label, &depth)); 6116 PetscCall(DMLabelGetValue(label, point, &h)); 6117 h = depth - 1 - h; 6118 if (h) { 6119 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6120 } else { 6121 *dspace = dsp; 6122 } 6123 } 6124 } 6125 PetscFunctionReturn(PETSC_SUCCESS); 6126 } 6127 6128 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6129 { 6130 PetscScalar *array; 6131 const PetscScalar *vArray; 6132 const PetscInt *cone, *coneO; 6133 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6134 6135 PetscFunctionBeginHot; 6136 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6137 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6138 PetscCall(DMPlexGetCone(dm, point, &cone)); 6139 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6140 if (!values || !*values) { 6141 if ((point >= pStart) && (point < pEnd)) { 6142 PetscInt dof; 6143 6144 PetscCall(PetscSectionGetDof(section, point, &dof)); 6145 size += dof; 6146 } 6147 for (p = 0; p < numPoints; ++p) { 6148 const PetscInt cp = cone[p]; 6149 PetscInt dof; 6150 6151 if ((cp < pStart) || (cp >= pEnd)) continue; 6152 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6153 size += dof; 6154 } 6155 if (!values) { 6156 if (csize) *csize = size; 6157 PetscFunctionReturn(PETSC_SUCCESS); 6158 } 6159 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6160 } else { 6161 array = *values; 6162 } 6163 size = 0; 6164 PetscCall(VecGetArrayRead(v, &vArray)); 6165 if ((point >= pStart) && (point < pEnd)) { 6166 PetscInt dof, off, d; 6167 const PetscScalar *varr; 6168 6169 PetscCall(PetscSectionGetDof(section, point, &dof)); 6170 PetscCall(PetscSectionGetOffset(section, point, &off)); 6171 varr = PetscSafePointerPlusOffset(vArray, off); 6172 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6173 size += dof; 6174 } 6175 for (p = 0; p < numPoints; ++p) { 6176 const PetscInt cp = cone[p]; 6177 PetscInt o = coneO[p]; 6178 PetscInt dof, off, d; 6179 const PetscScalar *varr; 6180 6181 if ((cp < pStart) || (cp >= pEnd)) continue; 6182 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6183 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6184 varr = PetscSafePointerPlusOffset(vArray, off); 6185 if (o >= 0) { 6186 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6187 } else { 6188 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6189 } 6190 size += dof; 6191 } 6192 PetscCall(VecRestoreArrayRead(v, &vArray)); 6193 if (!*values) { 6194 if (csize) *csize = size; 6195 *values = array; 6196 } else { 6197 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6198 *csize = size; 6199 } 6200 PetscFunctionReturn(PETSC_SUCCESS); 6201 } 6202 6203 /* Compress out points not in the section */ 6204 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6205 { 6206 const PetscInt np = *numPoints; 6207 PetscInt pStart, pEnd, p, q; 6208 6209 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6210 for (p = 0, q = 0; p < np; ++p) { 6211 const PetscInt r = points[p * 2]; 6212 if ((r >= pStart) && (r < pEnd)) { 6213 points[q * 2] = r; 6214 points[q * 2 + 1] = points[p * 2 + 1]; 6215 ++q; 6216 } 6217 } 6218 *numPoints = q; 6219 return PETSC_SUCCESS; 6220 } 6221 6222 /* Compressed closure does not apply closure permutation */ 6223 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6224 { 6225 const PetscInt *cla = NULL; 6226 PetscInt np, *pts = NULL; 6227 6228 PetscFunctionBeginHot; 6229 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6230 if (!ornt && *clPoints) { 6231 PetscInt dof, off; 6232 6233 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6234 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6235 PetscCall(ISGetIndices(*clPoints, &cla)); 6236 np = dof / 2; 6237 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6238 } else { 6239 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6240 PetscCall(CompressPoints_Private(section, &np, pts)); 6241 } 6242 *numPoints = np; 6243 *points = pts; 6244 *clp = cla; 6245 PetscFunctionReturn(PETSC_SUCCESS); 6246 } 6247 6248 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6249 { 6250 PetscFunctionBeginHot; 6251 if (!*clPoints) { 6252 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6253 } else { 6254 PetscCall(ISRestoreIndices(*clPoints, clp)); 6255 } 6256 *numPoints = 0; 6257 *points = NULL; 6258 *clSec = NULL; 6259 *clPoints = NULL; 6260 *clp = NULL; 6261 PetscFunctionReturn(PETSC_SUCCESS); 6262 } 6263 6264 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6265 { 6266 PetscInt offset = 0, p; 6267 const PetscInt **perms = NULL; 6268 const PetscScalar **flips = NULL; 6269 6270 PetscFunctionBeginHot; 6271 *size = 0; 6272 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6273 for (p = 0; p < numPoints; p++) { 6274 const PetscInt point = points[2 * p]; 6275 const PetscInt *perm = perms ? perms[p] : NULL; 6276 const PetscScalar *flip = flips ? flips[p] : NULL; 6277 PetscInt dof, off, d; 6278 const PetscScalar *varr; 6279 6280 PetscCall(PetscSectionGetDof(section, point, &dof)); 6281 PetscCall(PetscSectionGetOffset(section, point, &off)); 6282 varr = PetscSafePointerPlusOffset(vArray, off); 6283 if (clperm) { 6284 if (perm) { 6285 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6286 } else { 6287 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6288 } 6289 if (flip) { 6290 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6291 } 6292 } else { 6293 if (perm) { 6294 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6295 } else { 6296 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6297 } 6298 if (flip) { 6299 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6300 } 6301 } 6302 offset += dof; 6303 } 6304 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6305 *size = offset; 6306 PetscFunctionReturn(PETSC_SUCCESS); 6307 } 6308 6309 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[]) 6310 { 6311 PetscInt offset = 0, f; 6312 6313 PetscFunctionBeginHot; 6314 *size = 0; 6315 for (f = 0; f < numFields; ++f) { 6316 PetscInt p; 6317 const PetscInt **perms = NULL; 6318 const PetscScalar **flips = NULL; 6319 6320 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6321 for (p = 0; p < numPoints; p++) { 6322 const PetscInt point = points[2 * p]; 6323 PetscInt fdof, foff, b; 6324 const PetscScalar *varr; 6325 const PetscInt *perm = perms ? perms[p] : NULL; 6326 const PetscScalar *flip = flips ? flips[p] : NULL; 6327 6328 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6329 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6330 varr = &vArray[foff]; 6331 if (clperm) { 6332 if (perm) { 6333 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6334 } else { 6335 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6336 } 6337 if (flip) { 6338 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6339 } 6340 } else { 6341 if (perm) { 6342 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6343 } else { 6344 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6345 } 6346 if (flip) { 6347 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6348 } 6349 } 6350 offset += fdof; 6351 } 6352 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6353 } 6354 *size = offset; 6355 PetscFunctionReturn(PETSC_SUCCESS); 6356 } 6357 6358 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6359 { 6360 PetscSection clSection; 6361 IS clPoints; 6362 PetscInt *points = NULL; 6363 const PetscInt *clp, *perm = NULL; 6364 PetscInt depth, numFields, numPoints, asize; 6365 6366 PetscFunctionBeginHot; 6367 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6368 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6369 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6370 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6371 PetscCall(DMPlexGetDepth(dm, &depth)); 6372 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6373 if (depth == 1 && numFields < 2) { 6374 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6375 PetscFunctionReturn(PETSC_SUCCESS); 6376 } 6377 /* Get points */ 6378 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6379 /* Get sizes */ 6380 asize = 0; 6381 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6382 PetscInt dof; 6383 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6384 asize += dof; 6385 } 6386 if (values) { 6387 const PetscScalar *vArray; 6388 PetscInt size; 6389 6390 if (*values) { 6391 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); 6392 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6393 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6394 PetscCall(VecGetArrayRead(v, &vArray)); 6395 /* Get values */ 6396 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6397 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6398 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6399 /* Cleanup array */ 6400 PetscCall(VecRestoreArrayRead(v, &vArray)); 6401 } 6402 if (csize) *csize = asize; 6403 /* Cleanup points */ 6404 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6405 PetscFunctionReturn(PETSC_SUCCESS); 6406 } 6407 6408 /*@C 6409 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6410 6411 Not collective 6412 6413 Input Parameters: 6414 + dm - The `DM` 6415 . section - The section describing the layout in `v`, or `NULL` to use the default section 6416 . v - The local vector 6417 - point - The point in the `DM` 6418 6419 Input/Output Parameters: 6420 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6421 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6422 if the user provided `NULL`, it is a borrowed array and should not be freed 6423 6424 Level: intermediate 6425 6426 Notes: 6427 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6428 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6429 assembly function, and a user may already have allocated storage for this operation. 6430 6431 A typical use could be 6432 .vb 6433 values = NULL; 6434 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6435 for (cl = 0; cl < clSize; ++cl) { 6436 <Compute on closure> 6437 } 6438 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6439 .ve 6440 or 6441 .vb 6442 PetscMalloc1(clMaxSize, &values); 6443 for (p = pStart; p < pEnd; ++p) { 6444 clSize = clMaxSize; 6445 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6446 for (cl = 0; cl < clSize; ++cl) { 6447 <Compute on closure> 6448 } 6449 } 6450 PetscFree(values); 6451 .ve 6452 6453 Fortran Notes: 6454 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6455 6456 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6457 @*/ 6458 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6459 { 6460 PetscFunctionBeginHot; 6461 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6462 PetscFunctionReturn(PETSC_SUCCESS); 6463 } 6464 6465 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6466 { 6467 DMLabel depthLabel; 6468 PetscSection clSection; 6469 IS clPoints; 6470 PetscScalar *array; 6471 const PetscScalar *vArray; 6472 PetscInt *points = NULL; 6473 const PetscInt *clp, *perm = NULL; 6474 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6475 6476 PetscFunctionBeginHot; 6477 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6478 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6479 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6480 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6481 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6482 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6483 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6484 if (mdepth == 1 && numFields < 2) { 6485 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6486 PetscFunctionReturn(PETSC_SUCCESS); 6487 } 6488 /* Get points */ 6489 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6490 for (clsize = 0, p = 0; p < Np; p++) { 6491 PetscInt dof; 6492 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6493 clsize += dof; 6494 } 6495 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6496 /* Filter points */ 6497 for (p = 0; p < numPoints * 2; p += 2) { 6498 PetscInt dep; 6499 6500 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6501 if (dep != depth) continue; 6502 points[Np * 2 + 0] = points[p]; 6503 points[Np * 2 + 1] = points[p + 1]; 6504 ++Np; 6505 } 6506 /* Get array */ 6507 if (!values || !*values) { 6508 PetscInt asize = 0, dof; 6509 6510 for (p = 0; p < Np * 2; p += 2) { 6511 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6512 asize += dof; 6513 } 6514 if (!values) { 6515 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6516 if (csize) *csize = asize; 6517 PetscFunctionReturn(PETSC_SUCCESS); 6518 } 6519 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6520 } else { 6521 array = *values; 6522 } 6523 PetscCall(VecGetArrayRead(v, &vArray)); 6524 /* Get values */ 6525 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6526 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6527 /* Cleanup points */ 6528 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6529 /* Cleanup array */ 6530 PetscCall(VecRestoreArrayRead(v, &vArray)); 6531 if (!*values) { 6532 if (csize) *csize = size; 6533 *values = array; 6534 } else { 6535 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6536 *csize = size; 6537 } 6538 PetscFunctionReturn(PETSC_SUCCESS); 6539 } 6540 6541 /*@C 6542 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6543 6544 Not collective 6545 6546 Input Parameters: 6547 + dm - The `DM` 6548 . section - The section describing the layout in `v`, or `NULL` to use the default section 6549 . v - The local vector 6550 . point - The point in the `DM` 6551 . csize - The number of values in the closure, or `NULL` 6552 - values - The array of values, which is a borrowed array and should not be freed 6553 6554 Level: intermediate 6555 6556 Note: 6557 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6558 6559 Fortran Notes: 6560 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6561 6562 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6563 @*/ 6564 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6565 { 6566 PetscInt size = 0; 6567 6568 PetscFunctionBegin; 6569 /* Should work without recalculating size */ 6570 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6571 *values = NULL; 6572 PetscFunctionReturn(PETSC_SUCCESS); 6573 } 6574 6575 static inline void add(PetscScalar *x, PetscScalar y) 6576 { 6577 *x += y; 6578 } 6579 static inline void insert(PetscScalar *x, PetscScalar y) 6580 { 6581 *x = y; 6582 } 6583 6584 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[]) 6585 { 6586 PetscInt cdof; /* The number of constraints on this point */ 6587 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6588 PetscScalar *a; 6589 PetscInt off, cind = 0, k; 6590 6591 PetscFunctionBegin; 6592 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6593 PetscCall(PetscSectionGetOffset(section, point, &off)); 6594 a = &array[off]; 6595 if (!cdof || setBC) { 6596 if (clperm) { 6597 if (perm) { 6598 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6599 } else { 6600 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6601 } 6602 } else { 6603 if (perm) { 6604 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6605 } else { 6606 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6607 } 6608 } 6609 } else { 6610 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6611 if (clperm) { 6612 if (perm) { 6613 for (k = 0; k < dof; ++k) { 6614 if ((cind < cdof) && (k == cdofs[cind])) { 6615 ++cind; 6616 continue; 6617 } 6618 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6619 } 6620 } else { 6621 for (k = 0; k < dof; ++k) { 6622 if ((cind < cdof) && (k == cdofs[cind])) { 6623 ++cind; 6624 continue; 6625 } 6626 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6627 } 6628 } 6629 } else { 6630 if (perm) { 6631 for (k = 0; k < dof; ++k) { 6632 if ((cind < cdof) && (k == cdofs[cind])) { 6633 ++cind; 6634 continue; 6635 } 6636 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6637 } 6638 } else { 6639 for (k = 0; k < dof; ++k) { 6640 if ((cind < cdof) && (k == cdofs[cind])) { 6641 ++cind; 6642 continue; 6643 } 6644 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6645 } 6646 } 6647 } 6648 } 6649 PetscFunctionReturn(PETSC_SUCCESS); 6650 } 6651 6652 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[]) 6653 { 6654 PetscInt cdof; /* The number of constraints on this point */ 6655 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6656 PetscScalar *a; 6657 PetscInt off, cind = 0, k; 6658 6659 PetscFunctionBegin; 6660 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6661 PetscCall(PetscSectionGetOffset(section, point, &off)); 6662 a = &array[off]; 6663 if (cdof) { 6664 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6665 if (clperm) { 6666 if (perm) { 6667 for (k = 0; k < dof; ++k) { 6668 if ((cind < cdof) && (k == cdofs[cind])) { 6669 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6670 cind++; 6671 } 6672 } 6673 } else { 6674 for (k = 0; k < dof; ++k) { 6675 if ((cind < cdof) && (k == cdofs[cind])) { 6676 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6677 cind++; 6678 } 6679 } 6680 } 6681 } else { 6682 if (perm) { 6683 for (k = 0; k < dof; ++k) { 6684 if ((cind < cdof) && (k == cdofs[cind])) { 6685 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6686 cind++; 6687 } 6688 } 6689 } else { 6690 for (k = 0; k < dof; ++k) { 6691 if ((cind < cdof) && (k == cdofs[cind])) { 6692 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6693 cind++; 6694 } 6695 } 6696 } 6697 } 6698 } 6699 PetscFunctionReturn(PETSC_SUCCESS); 6700 } 6701 6702 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[]) 6703 { 6704 PetscScalar *a; 6705 PetscInt fdof, foff, fcdof, foffset = *offset; 6706 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6707 PetscInt cind = 0, b; 6708 6709 PetscFunctionBegin; 6710 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6711 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6712 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6713 a = &array[foff]; 6714 if (!fcdof || setBC) { 6715 if (clperm) { 6716 if (perm) { 6717 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6718 } else { 6719 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6720 } 6721 } else { 6722 if (perm) { 6723 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6724 } else { 6725 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6726 } 6727 } 6728 } else { 6729 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6730 if (clperm) { 6731 if (perm) { 6732 for (b = 0; b < fdof; b++) { 6733 if ((cind < fcdof) && (b == fcdofs[cind])) { 6734 ++cind; 6735 continue; 6736 } 6737 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6738 } 6739 } else { 6740 for (b = 0; b < fdof; b++) { 6741 if ((cind < fcdof) && (b == fcdofs[cind])) { 6742 ++cind; 6743 continue; 6744 } 6745 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6746 } 6747 } 6748 } else { 6749 if (perm) { 6750 for (b = 0; b < fdof; b++) { 6751 if ((cind < fcdof) && (b == fcdofs[cind])) { 6752 ++cind; 6753 continue; 6754 } 6755 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6756 } 6757 } else { 6758 for (b = 0; b < fdof; b++) { 6759 if ((cind < fcdof) && (b == fcdofs[cind])) { 6760 ++cind; 6761 continue; 6762 } 6763 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6764 } 6765 } 6766 } 6767 } 6768 *offset += fdof; 6769 PetscFunctionReturn(PETSC_SUCCESS); 6770 } 6771 6772 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[]) 6773 { 6774 PetscScalar *a; 6775 PetscInt fdof, foff, fcdof, foffset = *offset; 6776 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6777 PetscInt Nc, cind = 0, ncind = 0, b; 6778 PetscBool ncSet, fcSet; 6779 6780 PetscFunctionBegin; 6781 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6782 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6783 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6784 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6785 a = &array[foff]; 6786 if (fcdof) { 6787 /* We just override fcdof and fcdofs with Ncc and comps */ 6788 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6789 if (clperm) { 6790 if (perm) { 6791 if (comps) { 6792 for (b = 0; b < fdof; b++) { 6793 ncSet = fcSet = PETSC_FALSE; 6794 if (b % Nc == comps[ncind]) { 6795 ncind = (ncind + 1) % Ncc; 6796 ncSet = PETSC_TRUE; 6797 } 6798 if ((cind < fcdof) && (b == fcdofs[cind])) { 6799 ++cind; 6800 fcSet = PETSC_TRUE; 6801 } 6802 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6803 } 6804 } else { 6805 for (b = 0; b < fdof; b++) { 6806 if ((cind < fcdof) && (b == fcdofs[cind])) { 6807 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6808 ++cind; 6809 } 6810 } 6811 } 6812 } else { 6813 if (comps) { 6814 for (b = 0; b < fdof; b++) { 6815 ncSet = fcSet = PETSC_FALSE; 6816 if (b % Nc == comps[ncind]) { 6817 ncind = (ncind + 1) % Ncc; 6818 ncSet = PETSC_TRUE; 6819 } 6820 if ((cind < fcdof) && (b == fcdofs[cind])) { 6821 ++cind; 6822 fcSet = PETSC_TRUE; 6823 } 6824 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6825 } 6826 } else { 6827 for (b = 0; b < fdof; b++) { 6828 if ((cind < fcdof) && (b == fcdofs[cind])) { 6829 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6830 ++cind; 6831 } 6832 } 6833 } 6834 } 6835 } else { 6836 if (perm) { 6837 if (comps) { 6838 for (b = 0; b < fdof; b++) { 6839 ncSet = fcSet = PETSC_FALSE; 6840 if (b % Nc == comps[ncind]) { 6841 ncind = (ncind + 1) % Ncc; 6842 ncSet = PETSC_TRUE; 6843 } 6844 if ((cind < fcdof) && (b == fcdofs[cind])) { 6845 ++cind; 6846 fcSet = PETSC_TRUE; 6847 } 6848 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6849 } 6850 } else { 6851 for (b = 0; b < fdof; b++) { 6852 if ((cind < fcdof) && (b == fcdofs[cind])) { 6853 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6854 ++cind; 6855 } 6856 } 6857 } 6858 } else { 6859 if (comps) { 6860 for (b = 0; b < fdof; b++) { 6861 ncSet = fcSet = PETSC_FALSE; 6862 if (b % Nc == comps[ncind]) { 6863 ncind = (ncind + 1) % Ncc; 6864 ncSet = PETSC_TRUE; 6865 } 6866 if ((cind < fcdof) && (b == fcdofs[cind])) { 6867 ++cind; 6868 fcSet = PETSC_TRUE; 6869 } 6870 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6871 } 6872 } else { 6873 for (b = 0; b < fdof; b++) { 6874 if ((cind < fcdof) && (b == fcdofs[cind])) { 6875 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6876 ++cind; 6877 } 6878 } 6879 } 6880 } 6881 } 6882 } 6883 *offset += fdof; 6884 PetscFunctionReturn(PETSC_SUCCESS); 6885 } 6886 6887 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6888 { 6889 PetscScalar *array; 6890 const PetscInt *cone, *coneO; 6891 PetscInt pStart, pEnd, p, numPoints, off, dof; 6892 6893 PetscFunctionBeginHot; 6894 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6895 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6896 PetscCall(DMPlexGetCone(dm, point, &cone)); 6897 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6898 PetscCall(VecGetArray(v, &array)); 6899 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6900 const PetscInt cp = !p ? point : cone[p - 1]; 6901 const PetscInt o = !p ? 0 : coneO[p - 1]; 6902 6903 if ((cp < pStart) || (cp >= pEnd)) { 6904 dof = 0; 6905 continue; 6906 } 6907 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6908 /* ADD_VALUES */ 6909 { 6910 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6911 PetscScalar *a; 6912 PetscInt cdof, coff, cind = 0, k; 6913 6914 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6915 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6916 a = &array[coff]; 6917 if (!cdof) { 6918 if (o >= 0) { 6919 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6920 } else { 6921 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6922 } 6923 } else { 6924 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6925 if (o >= 0) { 6926 for (k = 0; k < dof; ++k) { 6927 if ((cind < cdof) && (k == cdofs[cind])) { 6928 ++cind; 6929 continue; 6930 } 6931 a[k] += values[off + k]; 6932 } 6933 } else { 6934 for (k = 0; k < dof; ++k) { 6935 if ((cind < cdof) && (k == cdofs[cind])) { 6936 ++cind; 6937 continue; 6938 } 6939 a[k] += values[off + dof - k - 1]; 6940 } 6941 } 6942 } 6943 } 6944 } 6945 PetscCall(VecRestoreArray(v, &array)); 6946 PetscFunctionReturn(PETSC_SUCCESS); 6947 } 6948 6949 /*@C 6950 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6951 6952 Not collective 6953 6954 Input Parameters: 6955 + dm - The `DM` 6956 . section - The section describing the layout in `v`, or `NULL` to use the default section 6957 . v - The local vector 6958 . point - The point in the `DM` 6959 . values - The array of values 6960 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6961 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6962 6963 Level: intermediate 6964 6965 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6966 @*/ 6967 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6968 { 6969 PetscSection clSection; 6970 IS clPoints; 6971 PetscScalar *array; 6972 PetscInt *points = NULL; 6973 const PetscInt *clp, *clperm = NULL; 6974 PetscInt depth, numFields, numPoints, p, clsize; 6975 6976 PetscFunctionBeginHot; 6977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6978 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6979 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6980 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6981 PetscCall(DMPlexGetDepth(dm, &depth)); 6982 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6983 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6984 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6985 PetscFunctionReturn(PETSC_SUCCESS); 6986 } 6987 /* Get points */ 6988 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6989 for (clsize = 0, p = 0; p < numPoints; p++) { 6990 PetscInt dof; 6991 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6992 clsize += dof; 6993 } 6994 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6995 /* Get array */ 6996 PetscCall(VecGetArray(v, &array)); 6997 /* Get values */ 6998 if (numFields > 0) { 6999 PetscInt offset = 0, f; 7000 for (f = 0; f < numFields; ++f) { 7001 const PetscInt **perms = NULL; 7002 const PetscScalar **flips = NULL; 7003 7004 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7005 switch (mode) { 7006 case INSERT_VALUES: 7007 for (p = 0; p < numPoints; p++) { 7008 const PetscInt point = points[2 * p]; 7009 const PetscInt *perm = perms ? perms[p] : NULL; 7010 const PetscScalar *flip = flips ? flips[p] : NULL; 7011 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7012 } 7013 break; 7014 case INSERT_ALL_VALUES: 7015 for (p = 0; p < numPoints; p++) { 7016 const PetscInt point = points[2 * p]; 7017 const PetscInt *perm = perms ? perms[p] : NULL; 7018 const PetscScalar *flip = flips ? flips[p] : NULL; 7019 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7020 } 7021 break; 7022 case INSERT_BC_VALUES: 7023 for (p = 0; p < numPoints; p++) { 7024 const PetscInt point = points[2 * p]; 7025 const PetscInt *perm = perms ? perms[p] : NULL; 7026 const PetscScalar *flip = flips ? flips[p] : NULL; 7027 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7028 } 7029 break; 7030 case ADD_VALUES: 7031 for (p = 0; p < numPoints; p++) { 7032 const PetscInt point = points[2 * p]; 7033 const PetscInt *perm = perms ? perms[p] : NULL; 7034 const PetscScalar *flip = flips ? flips[p] : NULL; 7035 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7036 } 7037 break; 7038 case ADD_ALL_VALUES: 7039 for (p = 0; p < numPoints; p++) { 7040 const PetscInt point = points[2 * p]; 7041 const PetscInt *perm = perms ? perms[p] : NULL; 7042 const PetscScalar *flip = flips ? flips[p] : NULL; 7043 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7044 } 7045 break; 7046 case ADD_BC_VALUES: 7047 for (p = 0; p < numPoints; p++) { 7048 const PetscInt point = points[2 * p]; 7049 const PetscInt *perm = perms ? perms[p] : NULL; 7050 const PetscScalar *flip = flips ? flips[p] : NULL; 7051 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7052 } 7053 break; 7054 default: 7055 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7056 } 7057 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7058 } 7059 } else { 7060 PetscInt dof, off; 7061 const PetscInt **perms = NULL; 7062 const PetscScalar **flips = NULL; 7063 7064 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7065 switch (mode) { 7066 case INSERT_VALUES: 7067 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7068 const PetscInt point = points[2 * p]; 7069 const PetscInt *perm = perms ? perms[p] : NULL; 7070 const PetscScalar *flip = flips ? flips[p] : NULL; 7071 PetscCall(PetscSectionGetDof(section, point, &dof)); 7072 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7073 } 7074 break; 7075 case INSERT_ALL_VALUES: 7076 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7077 const PetscInt point = points[2 * p]; 7078 const PetscInt *perm = perms ? perms[p] : NULL; 7079 const PetscScalar *flip = flips ? flips[p] : NULL; 7080 PetscCall(PetscSectionGetDof(section, point, &dof)); 7081 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7082 } 7083 break; 7084 case INSERT_BC_VALUES: 7085 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7086 const PetscInt point = points[2 * p]; 7087 const PetscInt *perm = perms ? perms[p] : NULL; 7088 const PetscScalar *flip = flips ? flips[p] : NULL; 7089 PetscCall(PetscSectionGetDof(section, point, &dof)); 7090 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7091 } 7092 break; 7093 case ADD_VALUES: 7094 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7095 const PetscInt point = points[2 * p]; 7096 const PetscInt *perm = perms ? perms[p] : NULL; 7097 const PetscScalar *flip = flips ? flips[p] : NULL; 7098 PetscCall(PetscSectionGetDof(section, point, &dof)); 7099 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7100 } 7101 break; 7102 case ADD_ALL_VALUES: 7103 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7104 const PetscInt point = points[2 * p]; 7105 const PetscInt *perm = perms ? perms[p] : NULL; 7106 const PetscScalar *flip = flips ? flips[p] : NULL; 7107 PetscCall(PetscSectionGetDof(section, point, &dof)); 7108 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7109 } 7110 break; 7111 case ADD_BC_VALUES: 7112 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7113 const PetscInt point = points[2 * p]; 7114 const PetscInt *perm = perms ? perms[p] : NULL; 7115 const PetscScalar *flip = flips ? flips[p] : NULL; 7116 PetscCall(PetscSectionGetDof(section, point, &dof)); 7117 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7118 } 7119 break; 7120 default: 7121 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7122 } 7123 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7124 } 7125 /* Cleanup points */ 7126 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7127 /* Cleanup array */ 7128 PetscCall(VecRestoreArray(v, &array)); 7129 PetscFunctionReturn(PETSC_SUCCESS); 7130 } 7131 7132 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7133 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7134 { 7135 PetscFunctionBegin; 7136 *contains = PETSC_TRUE; 7137 if (label) { 7138 PetscInt fdof; 7139 7140 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7141 if (!*contains) { 7142 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7143 *offset += fdof; 7144 PetscFunctionReturn(PETSC_SUCCESS); 7145 } 7146 } 7147 PetscFunctionReturn(PETSC_SUCCESS); 7148 } 7149 7150 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7151 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) 7152 { 7153 PetscSection clSection; 7154 IS clPoints; 7155 PetscScalar *array; 7156 PetscInt *points = NULL; 7157 const PetscInt *clp; 7158 PetscInt numFields, numPoints, p; 7159 PetscInt offset = 0, f; 7160 7161 PetscFunctionBeginHot; 7162 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7163 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7164 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7165 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7166 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7167 /* Get points */ 7168 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7169 /* Get array */ 7170 PetscCall(VecGetArray(v, &array)); 7171 /* Get values */ 7172 for (f = 0; f < numFields; ++f) { 7173 const PetscInt **perms = NULL; 7174 const PetscScalar **flips = NULL; 7175 PetscBool contains; 7176 7177 if (!fieldActive[f]) { 7178 for (p = 0; p < numPoints * 2; p += 2) { 7179 PetscInt fdof; 7180 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7181 offset += fdof; 7182 } 7183 continue; 7184 } 7185 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7186 switch (mode) { 7187 case INSERT_VALUES: 7188 for (p = 0; p < numPoints; p++) { 7189 const PetscInt point = points[2 * p]; 7190 const PetscInt *perm = perms ? perms[p] : NULL; 7191 const PetscScalar *flip = flips ? flips[p] : NULL; 7192 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7193 if (!contains) continue; 7194 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7195 } 7196 break; 7197 case INSERT_ALL_VALUES: 7198 for (p = 0; p < numPoints; p++) { 7199 const PetscInt point = points[2 * p]; 7200 const PetscInt *perm = perms ? perms[p] : NULL; 7201 const PetscScalar *flip = flips ? flips[p] : NULL; 7202 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7203 if (!contains) continue; 7204 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7205 } 7206 break; 7207 case INSERT_BC_VALUES: 7208 for (p = 0; p < numPoints; p++) { 7209 const PetscInt point = points[2 * p]; 7210 const PetscInt *perm = perms ? perms[p] : NULL; 7211 const PetscScalar *flip = flips ? flips[p] : NULL; 7212 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7213 if (!contains) continue; 7214 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7215 } 7216 break; 7217 case ADD_VALUES: 7218 for (p = 0; p < numPoints; p++) { 7219 const PetscInt point = points[2 * p]; 7220 const PetscInt *perm = perms ? perms[p] : NULL; 7221 const PetscScalar *flip = flips ? flips[p] : NULL; 7222 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7223 if (!contains) continue; 7224 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7225 } 7226 break; 7227 case ADD_ALL_VALUES: 7228 for (p = 0; p < numPoints; p++) { 7229 const PetscInt point = points[2 * p]; 7230 const PetscInt *perm = perms ? perms[p] : NULL; 7231 const PetscScalar *flip = flips ? flips[p] : NULL; 7232 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7233 if (!contains) continue; 7234 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7235 } 7236 break; 7237 default: 7238 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7239 } 7240 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7241 } 7242 /* Cleanup points */ 7243 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7244 /* Cleanup array */ 7245 PetscCall(VecRestoreArray(v, &array)); 7246 PetscFunctionReturn(PETSC_SUCCESS); 7247 } 7248 7249 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7250 { 7251 PetscMPIInt rank; 7252 PetscInt i, j; 7253 7254 PetscFunctionBegin; 7255 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7256 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7257 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7258 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7259 numCIndices = numCIndices ? numCIndices : numRIndices; 7260 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7261 for (i = 0; i < numRIndices; i++) { 7262 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7263 for (j = 0; j < numCIndices; j++) { 7264 #if defined(PETSC_USE_COMPLEX) 7265 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7266 #else 7267 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7268 #endif 7269 } 7270 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7271 } 7272 PetscFunctionReturn(PETSC_SUCCESS); 7273 } 7274 7275 /* 7276 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7277 7278 Input Parameters: 7279 + section - The section for this data layout 7280 . islocal - Is the section (and thus indices being requested) local or global? 7281 . point - The point contributing dofs with these indices 7282 . off - The global offset of this point 7283 . loff - The local offset of each field 7284 . setBC - The flag determining whether to include indices of boundary values 7285 . perm - A permutation of the dofs on this point, or NULL 7286 - indperm - A permutation of the entire indices array, or NULL 7287 7288 Output Parameter: 7289 . indices - Indices for dofs on this point 7290 7291 Level: developer 7292 7293 Note: The indices could be local or global, depending on the value of 'off'. 7294 */ 7295 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7296 { 7297 PetscInt dof; /* The number of unknowns on this point */ 7298 PetscInt cdof; /* The number of constraints on this point */ 7299 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7300 PetscInt cind = 0, k; 7301 7302 PetscFunctionBegin; 7303 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7304 PetscCall(PetscSectionGetDof(section, point, &dof)); 7305 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7306 if (!cdof || setBC) { 7307 for (k = 0; k < dof; ++k) { 7308 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7309 const PetscInt ind = indperm ? indperm[preind] : preind; 7310 7311 indices[ind] = off + k; 7312 } 7313 } else { 7314 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7315 for (k = 0; k < dof; ++k) { 7316 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7317 const PetscInt ind = indperm ? indperm[preind] : preind; 7318 7319 if ((cind < cdof) && (k == cdofs[cind])) { 7320 /* Insert check for returning constrained indices */ 7321 indices[ind] = -(off + k + 1); 7322 ++cind; 7323 } else { 7324 indices[ind] = off + k - (islocal ? 0 : cind); 7325 } 7326 } 7327 } 7328 *loff += dof; 7329 PetscFunctionReturn(PETSC_SUCCESS); 7330 } 7331 7332 /* 7333 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7334 7335 Input Parameters: 7336 + section - a section (global or local) 7337 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7338 . point - point within section 7339 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7340 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7341 . setBC - identify constrained (boundary condition) points via involution. 7342 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7343 . permsoff - offset 7344 - indperm - index permutation 7345 7346 Output Parameter: 7347 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7348 . indices - array to hold indices (as defined by section) of each dof associated with point 7349 7350 Notes: 7351 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7352 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7353 in the local vector. 7354 7355 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7356 significant). It is invalid to call with a global section and setBC=true. 7357 7358 Developer Note: 7359 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7360 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7361 offset could be obtained from the section instead of passing it explicitly as we do now. 7362 7363 Example: 7364 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7365 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7366 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7367 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. 7368 7369 Level: developer 7370 */ 7371 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[]) 7372 { 7373 PetscInt numFields, foff, f; 7374 7375 PetscFunctionBegin; 7376 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7377 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7378 for (f = 0, foff = 0; f < numFields; ++f) { 7379 PetscInt fdof, cfdof; 7380 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7381 PetscInt cind = 0, b; 7382 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7383 7384 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7385 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7386 if (!cfdof || setBC) { 7387 for (b = 0; b < fdof; ++b) { 7388 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7389 const PetscInt ind = indperm ? indperm[preind] : preind; 7390 7391 indices[ind] = off + foff + b; 7392 } 7393 } else { 7394 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7395 for (b = 0; b < fdof; ++b) { 7396 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7397 const PetscInt ind = indperm ? indperm[preind] : preind; 7398 7399 if ((cind < cfdof) && (b == fcdofs[cind])) { 7400 indices[ind] = -(off + foff + b + 1); 7401 ++cind; 7402 } else { 7403 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7404 } 7405 } 7406 } 7407 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7408 foffs[f] += fdof; 7409 } 7410 PetscFunctionReturn(PETSC_SUCCESS); 7411 } 7412 7413 /* 7414 This version believes the globalSection offsets for each field, rather than just the point offset 7415 7416 . foffs - The offset into 'indices' for each field, since it is segregated by field 7417 7418 Notes: 7419 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7420 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7421 */ 7422 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7423 { 7424 PetscInt numFields, foff, f; 7425 7426 PetscFunctionBegin; 7427 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7428 for (f = 0; f < numFields; ++f) { 7429 PetscInt fdof, cfdof; 7430 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7431 PetscInt cind = 0, b; 7432 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7433 7434 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7435 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7436 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7437 if (!cfdof) { 7438 for (b = 0; b < fdof; ++b) { 7439 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7440 const PetscInt ind = indperm ? indperm[preind] : preind; 7441 7442 indices[ind] = foff + b; 7443 } 7444 } else { 7445 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7446 for (b = 0; b < fdof; ++b) { 7447 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7448 const PetscInt ind = indperm ? indperm[preind] : preind; 7449 7450 if ((cind < cfdof) && (b == fcdofs[cind])) { 7451 indices[ind] = -(foff + b + 1); 7452 ++cind; 7453 } else { 7454 indices[ind] = foff + b - cind; 7455 } 7456 } 7457 } 7458 foffs[f] += fdof; 7459 } 7460 PetscFunctionReturn(PETSC_SUCCESS); 7461 } 7462 7463 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) 7464 { 7465 Mat cMat; 7466 PetscSection aSec, cSec; 7467 IS aIS; 7468 PetscInt aStart = -1, aEnd = -1; 7469 const PetscInt *anchors; 7470 PetscInt numFields, f, p, q, newP = 0; 7471 PetscInt newNumPoints = 0, newNumIndices = 0; 7472 PetscInt *newPoints, *indices, *newIndices; 7473 PetscInt maxAnchor, maxDof; 7474 PetscInt newOffsets[32]; 7475 PetscInt *pointMatOffsets[32]; 7476 PetscInt *newPointOffsets[32]; 7477 PetscScalar *pointMat[32]; 7478 PetscScalar *newValues = NULL, *tmpValues; 7479 PetscBool anyConstrained = PETSC_FALSE; 7480 7481 PetscFunctionBegin; 7482 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7483 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7484 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7485 7486 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7487 /* if there are point-to-point constraints */ 7488 if (aSec) { 7489 PetscCall(PetscArrayzero(newOffsets, 32)); 7490 PetscCall(ISGetIndices(aIS, &anchors)); 7491 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7492 /* figure out how many points are going to be in the new element matrix 7493 * (we allow double counting, because it's all just going to be summed 7494 * into the global matrix anyway) */ 7495 for (p = 0; p < 2 * numPoints; p += 2) { 7496 PetscInt b = points[p]; 7497 PetscInt bDof = 0, bSecDof; 7498 7499 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7500 if (!bSecDof) continue; 7501 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7502 if (bDof) { 7503 /* this point is constrained */ 7504 /* it is going to be replaced by its anchors */ 7505 PetscInt bOff, q; 7506 7507 anyConstrained = PETSC_TRUE; 7508 newNumPoints += bDof; 7509 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7510 for (q = 0; q < bDof; q++) { 7511 PetscInt a = anchors[bOff + q]; 7512 PetscInt aDof; 7513 7514 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7515 newNumIndices += aDof; 7516 for (f = 0; f < numFields; ++f) { 7517 PetscInt fDof; 7518 7519 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7520 newOffsets[f + 1] += fDof; 7521 } 7522 } 7523 } else { 7524 /* this point is not constrained */ 7525 newNumPoints++; 7526 newNumIndices += bSecDof; 7527 for (f = 0; f < numFields; ++f) { 7528 PetscInt fDof; 7529 7530 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7531 newOffsets[f + 1] += fDof; 7532 } 7533 } 7534 } 7535 } 7536 if (!anyConstrained) { 7537 if (outNumPoints) *outNumPoints = 0; 7538 if (outNumIndices) *outNumIndices = 0; 7539 if (outPoints) *outPoints = NULL; 7540 if (outValues) *outValues = NULL; 7541 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7542 PetscFunctionReturn(PETSC_SUCCESS); 7543 } 7544 7545 if (outNumPoints) *outNumPoints = newNumPoints; 7546 if (outNumIndices) *outNumIndices = newNumIndices; 7547 7548 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7549 7550 if (!outPoints && !outValues) { 7551 if (offsets) { 7552 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7553 } 7554 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7555 PetscFunctionReturn(PETSC_SUCCESS); 7556 } 7557 7558 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7559 7560 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7561 7562 /* workspaces */ 7563 if (numFields) { 7564 for (f = 0; f < numFields; f++) { 7565 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7566 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7567 } 7568 } else { 7569 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7570 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7571 } 7572 7573 /* get workspaces for the point-to-point matrices */ 7574 if (numFields) { 7575 PetscInt totalOffset, totalMatOffset; 7576 7577 for (p = 0; p < numPoints; p++) { 7578 PetscInt b = points[2 * p]; 7579 PetscInt bDof = 0, bSecDof; 7580 7581 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7582 if (!bSecDof) { 7583 for (f = 0; f < numFields; f++) { 7584 newPointOffsets[f][p + 1] = 0; 7585 pointMatOffsets[f][p + 1] = 0; 7586 } 7587 continue; 7588 } 7589 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7590 if (bDof) { 7591 for (f = 0; f < numFields; f++) { 7592 PetscInt fDof, q, bOff, allFDof = 0; 7593 7594 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7595 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7596 for (q = 0; q < bDof; q++) { 7597 PetscInt a = anchors[bOff + q]; 7598 PetscInt aFDof; 7599 7600 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7601 allFDof += aFDof; 7602 } 7603 newPointOffsets[f][p + 1] = allFDof; 7604 pointMatOffsets[f][p + 1] = fDof * allFDof; 7605 } 7606 } else { 7607 for (f = 0; f < numFields; f++) { 7608 PetscInt fDof; 7609 7610 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7611 newPointOffsets[f][p + 1] = fDof; 7612 pointMatOffsets[f][p + 1] = 0; 7613 } 7614 } 7615 } 7616 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7617 newPointOffsets[f][0] = totalOffset; 7618 pointMatOffsets[f][0] = totalMatOffset; 7619 for (p = 0; p < numPoints; p++) { 7620 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7621 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7622 } 7623 totalOffset = newPointOffsets[f][numPoints]; 7624 totalMatOffset = pointMatOffsets[f][numPoints]; 7625 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7626 } 7627 } else { 7628 for (p = 0; p < numPoints; p++) { 7629 PetscInt b = points[2 * p]; 7630 PetscInt bDof = 0, bSecDof; 7631 7632 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7633 if (!bSecDof) { 7634 newPointOffsets[0][p + 1] = 0; 7635 pointMatOffsets[0][p + 1] = 0; 7636 continue; 7637 } 7638 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7639 if (bDof) { 7640 PetscInt bOff, q, allDof = 0; 7641 7642 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7643 for (q = 0; q < bDof; q++) { 7644 PetscInt a = anchors[bOff + q], aDof; 7645 7646 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7647 allDof += aDof; 7648 } 7649 newPointOffsets[0][p + 1] = allDof; 7650 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7651 } else { 7652 newPointOffsets[0][p + 1] = bSecDof; 7653 pointMatOffsets[0][p + 1] = 0; 7654 } 7655 } 7656 newPointOffsets[0][0] = 0; 7657 pointMatOffsets[0][0] = 0; 7658 for (p = 0; p < numPoints; p++) { 7659 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7660 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7661 } 7662 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7663 } 7664 7665 /* output arrays */ 7666 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7667 7668 /* get the point-to-point matrices; construct newPoints */ 7669 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7670 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7671 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7672 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7673 if (numFields) { 7674 for (p = 0, newP = 0; p < numPoints; p++) { 7675 PetscInt b = points[2 * p]; 7676 PetscInt o = points[2 * p + 1]; 7677 PetscInt bDof = 0, bSecDof; 7678 7679 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7680 if (!bSecDof) continue; 7681 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7682 if (bDof) { 7683 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7684 7685 fStart[0] = 0; 7686 fEnd[0] = 0; 7687 for (f = 0; f < numFields; f++) { 7688 PetscInt fDof; 7689 7690 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7691 fStart[f + 1] = fStart[f] + fDof; 7692 fEnd[f + 1] = fStart[f + 1]; 7693 } 7694 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7695 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7696 7697 fAnchorStart[0] = 0; 7698 fAnchorEnd[0] = 0; 7699 for (f = 0; f < numFields; f++) { 7700 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7701 7702 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7703 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7704 } 7705 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7706 for (q = 0; q < bDof; q++) { 7707 PetscInt a = anchors[bOff + q], aOff; 7708 7709 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7710 newPoints[2 * (newP + q)] = a; 7711 newPoints[2 * (newP + q) + 1] = 0; 7712 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7713 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7714 } 7715 newP += bDof; 7716 7717 if (outValues) { 7718 /* get the point-to-point submatrix */ 7719 for (f = 0; f < numFields; f++) PetscCall(MatGetValues(cMat, fEnd[f] - fStart[f], indices + fStart[f], fAnchorEnd[f] - fAnchorStart[f], newIndices + fAnchorStart[f], pointMat[f] + pointMatOffsets[f][p])); 7720 } 7721 } else { 7722 newPoints[2 * newP] = b; 7723 newPoints[2 * newP + 1] = o; 7724 newP++; 7725 } 7726 } 7727 } else { 7728 for (p = 0; p < numPoints; p++) { 7729 PetscInt b = points[2 * p]; 7730 PetscInt o = points[2 * p + 1]; 7731 PetscInt bDof = 0, bSecDof; 7732 7733 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7734 if (!bSecDof) continue; 7735 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7736 if (bDof) { 7737 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7738 7739 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7740 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7741 7742 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7743 for (q = 0; q < bDof; q++) { 7744 PetscInt a = anchors[bOff + q], aOff; 7745 7746 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7747 7748 newPoints[2 * (newP + q)] = a; 7749 newPoints[2 * (newP + q) + 1] = 0; 7750 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7751 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7752 } 7753 newP += bDof; 7754 7755 /* get the point-to-point submatrix */ 7756 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7757 } else { 7758 newPoints[2 * newP] = b; 7759 newPoints[2 * newP + 1] = o; 7760 newP++; 7761 } 7762 } 7763 } 7764 7765 if (outValues) { 7766 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7767 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7768 /* multiply constraints on the right */ 7769 if (numFields) { 7770 for (f = 0; f < numFields; f++) { 7771 PetscInt oldOff = offsets[f]; 7772 7773 for (p = 0; p < numPoints; p++) { 7774 PetscInt cStart = newPointOffsets[f][p]; 7775 PetscInt b = points[2 * p]; 7776 PetscInt c, r, k; 7777 PetscInt dof; 7778 7779 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7780 if (!dof) continue; 7781 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7782 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7783 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7784 7785 for (r = 0; r < numIndices; r++) { 7786 for (c = 0; c < nCols; c++) { 7787 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7788 } 7789 } 7790 } else { 7791 /* copy this column as is */ 7792 for (r = 0; r < numIndices; r++) { 7793 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7794 } 7795 } 7796 oldOff += dof; 7797 } 7798 } 7799 } else { 7800 PetscInt oldOff = 0; 7801 for (p = 0; p < numPoints; p++) { 7802 PetscInt cStart = newPointOffsets[0][p]; 7803 PetscInt b = points[2 * p]; 7804 PetscInt c, r, k; 7805 PetscInt dof; 7806 7807 PetscCall(PetscSectionGetDof(section, b, &dof)); 7808 if (!dof) continue; 7809 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7810 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7811 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7812 7813 for (r = 0; r < numIndices; r++) { 7814 for (c = 0; c < nCols; c++) { 7815 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7816 } 7817 } 7818 } else { 7819 /* copy this column as is */ 7820 for (r = 0; r < numIndices; r++) { 7821 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7822 } 7823 } 7824 oldOff += dof; 7825 } 7826 } 7827 7828 if (multiplyLeft) { 7829 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7830 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7831 /* multiply constraints transpose on the left */ 7832 if (numFields) { 7833 for (f = 0; f < numFields; f++) { 7834 PetscInt oldOff = offsets[f]; 7835 7836 for (p = 0; p < numPoints; p++) { 7837 PetscInt rStart = newPointOffsets[f][p]; 7838 PetscInt b = points[2 * p]; 7839 PetscInt c, r, k; 7840 PetscInt dof; 7841 7842 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7843 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7844 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7845 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7846 7847 for (r = 0; r < nRows; r++) { 7848 for (c = 0; c < newNumIndices; c++) { 7849 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7850 } 7851 } 7852 } else { 7853 /* copy this row as is */ 7854 for (r = 0; r < dof; r++) { 7855 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7856 } 7857 } 7858 oldOff += dof; 7859 } 7860 } 7861 } else { 7862 PetscInt oldOff = 0; 7863 7864 for (p = 0; p < numPoints; p++) { 7865 PetscInt rStart = newPointOffsets[0][p]; 7866 PetscInt b = points[2 * p]; 7867 PetscInt c, r, k; 7868 PetscInt dof; 7869 7870 PetscCall(PetscSectionGetDof(section, b, &dof)); 7871 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7872 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7873 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7874 7875 for (r = 0; r < nRows; r++) { 7876 for (c = 0; c < newNumIndices; c++) { 7877 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7878 } 7879 } 7880 } else { 7881 /* copy this row as is */ 7882 for (r = 0; r < dof; r++) { 7883 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7884 } 7885 } 7886 oldOff += dof; 7887 } 7888 } 7889 7890 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7891 } else { 7892 newValues = tmpValues; 7893 } 7894 } 7895 7896 /* clean up */ 7897 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7898 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7899 7900 if (numFields) { 7901 for (f = 0; f < numFields; f++) { 7902 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7903 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7904 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7905 } 7906 } else { 7907 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7908 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7909 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7910 } 7911 PetscCall(ISRestoreIndices(aIS, &anchors)); 7912 7913 /* output */ 7914 if (outPoints) { 7915 *outPoints = newPoints; 7916 } else { 7917 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7918 } 7919 if (outValues) *outValues = newValues; 7920 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7921 PetscFunctionReturn(PETSC_SUCCESS); 7922 } 7923 7924 /*@C 7925 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7926 7927 Not collective 7928 7929 Input Parameters: 7930 + dm - The `DM` 7931 . section - The `PetscSection` describing the points (a local section) 7932 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7933 . point - The point defining the closure 7934 - useClPerm - Use the closure point permutation if available 7935 7936 Output Parameters: 7937 + numIndices - The number of dof indices in the closure of point with the input sections 7938 . indices - The dof indices 7939 . outOffsets - Array to write the field offsets into, or `NULL` 7940 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7941 7942 Level: advanced 7943 7944 Notes: 7945 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7946 7947 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7948 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7949 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7950 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7951 indices (with the above semantics) are implied. 7952 7953 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7954 `PetscSection`, `DMGetGlobalSection()` 7955 @*/ 7956 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7957 { 7958 /* Closure ordering */ 7959 PetscSection clSection; 7960 IS clPoints; 7961 const PetscInt *clp; 7962 PetscInt *points; 7963 const PetscInt *clperm = NULL; 7964 /* Dof permutation and sign flips */ 7965 const PetscInt **perms[32] = {NULL}; 7966 const PetscScalar **flips[32] = {NULL}; 7967 PetscScalar *valCopy = NULL; 7968 /* Hanging node constraints */ 7969 PetscInt *pointsC = NULL; 7970 PetscScalar *valuesC = NULL; 7971 PetscInt NclC, NiC; 7972 7973 PetscInt *idx; 7974 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7975 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7976 7977 PetscFunctionBeginHot; 7978 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7979 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7980 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7981 if (numIndices) PetscAssertPointer(numIndices, 6); 7982 if (indices) PetscAssertPointer(indices, 7); 7983 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7984 if (values) PetscAssertPointer(values, 9); 7985 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7986 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7987 PetscCall(PetscArrayzero(offsets, 32)); 7988 /* 1) Get points in closure */ 7989 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7990 if (useClPerm) { 7991 PetscInt depth, clsize; 7992 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7993 for (clsize = 0, p = 0; p < Ncl; p++) { 7994 PetscInt dof; 7995 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7996 clsize += dof; 7997 } 7998 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7999 } 8000 /* 2) Get number of indices on these points and field offsets from section */ 8001 for (p = 0; p < Ncl * 2; p += 2) { 8002 PetscInt dof, fdof; 8003 8004 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8005 for (f = 0; f < Nf; ++f) { 8006 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8007 offsets[f + 1] += fdof; 8008 } 8009 Ni += dof; 8010 } 8011 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8012 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8013 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8014 for (f = 0; f < PetscMax(1, Nf); ++f) { 8015 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8016 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8017 /* may need to apply sign changes to the element matrix */ 8018 if (values && flips[f]) { 8019 PetscInt foffset = offsets[f]; 8020 8021 for (p = 0; p < Ncl; ++p) { 8022 PetscInt pnt = points[2 * p], fdof; 8023 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8024 8025 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8026 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8027 if (flip) { 8028 PetscInt i, j, k; 8029 8030 if (!valCopy) { 8031 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8032 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8033 *values = valCopy; 8034 } 8035 for (i = 0; i < fdof; ++i) { 8036 PetscScalar fval = flip[i]; 8037 8038 for (k = 0; k < Ni; ++k) { 8039 valCopy[Ni * (foffset + i) + k] *= fval; 8040 valCopy[Ni * k + (foffset + i)] *= fval; 8041 } 8042 } 8043 } 8044 foffset += fdof; 8045 } 8046 } 8047 } 8048 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8049 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 8050 if (NclC) { 8051 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8052 for (f = 0; f < PetscMax(1, Nf); ++f) { 8053 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8054 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8055 } 8056 for (f = 0; f < PetscMax(1, Nf); ++f) { 8057 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8058 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8059 } 8060 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8061 Ncl = NclC; 8062 Ni = NiC; 8063 points = pointsC; 8064 if (values) *values = valuesC; 8065 } 8066 /* 5) Calculate indices */ 8067 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8068 if (Nf) { 8069 PetscInt idxOff; 8070 PetscBool useFieldOffsets; 8071 8072 if (outOffsets) { 8073 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8074 } 8075 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8076 if (useFieldOffsets) { 8077 for (p = 0; p < Ncl; ++p) { 8078 const PetscInt pnt = points[p * 2]; 8079 8080 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8081 } 8082 } else { 8083 for (p = 0; p < Ncl; ++p) { 8084 const PetscInt pnt = points[p * 2]; 8085 8086 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8087 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8088 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8089 * global section. */ 8090 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8091 } 8092 } 8093 } else { 8094 PetscInt off = 0, idxOff; 8095 8096 for (p = 0; p < Ncl; ++p) { 8097 const PetscInt pnt = points[p * 2]; 8098 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8099 8100 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8101 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8102 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8103 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8104 } 8105 } 8106 /* 6) Cleanup */ 8107 for (f = 0; f < PetscMax(1, Nf); ++f) { 8108 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8109 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8110 } 8111 if (NclC) { 8112 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8113 } else { 8114 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8115 } 8116 8117 if (numIndices) *numIndices = Ni; 8118 if (indices) *indices = idx; 8119 PetscFunctionReturn(PETSC_SUCCESS); 8120 } 8121 8122 /*@C 8123 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8124 8125 Not collective 8126 8127 Input Parameters: 8128 + dm - The `DM` 8129 . section - The `PetscSection` describing the points (a local section) 8130 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8131 . point - The point defining the closure 8132 - useClPerm - Use the closure point permutation if available 8133 8134 Output Parameters: 8135 + numIndices - The number of dof indices in the closure of point with the input sections 8136 . indices - The dof indices 8137 . outOffsets - Array to write the field offsets into, or `NULL` 8138 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8139 8140 Level: advanced 8141 8142 Notes: 8143 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8144 8145 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8146 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8147 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8148 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8149 indices (with the above semantics) are implied. 8150 8151 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8152 @*/ 8153 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8154 { 8155 PetscFunctionBegin; 8156 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8157 PetscAssertPointer(indices, 7); 8158 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8159 PetscFunctionReturn(PETSC_SUCCESS); 8160 } 8161 8162 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8163 { 8164 DM_Plex *mesh = (DM_Plex *)dm->data; 8165 PetscInt *indices; 8166 PetscInt numIndices; 8167 const PetscScalar *valuesOrig = values; 8168 PetscErrorCode ierr; 8169 8170 PetscFunctionBegin; 8171 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8172 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8173 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8174 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8175 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8176 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8177 8178 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8179 8180 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8181 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8182 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8183 if (ierr) { 8184 PetscMPIInt rank; 8185 8186 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8187 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8188 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8189 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8190 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8191 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8192 } 8193 if (mesh->printFEM > 1) { 8194 PetscInt i; 8195 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8196 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8197 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8198 } 8199 8200 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8201 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8202 PetscFunctionReturn(PETSC_SUCCESS); 8203 } 8204 8205 /*@C 8206 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8207 8208 Not collective 8209 8210 Input Parameters: 8211 + dm - The `DM` 8212 . section - The section describing the layout in `v`, or `NULL` to use the default section 8213 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8214 . A - The matrix 8215 . point - The point in the `DM` 8216 . values - The array of values 8217 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8218 8219 Level: intermediate 8220 8221 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8222 @*/ 8223 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8224 { 8225 PetscFunctionBegin; 8226 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8227 PetscFunctionReturn(PETSC_SUCCESS); 8228 } 8229 8230 /*@C 8231 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8232 8233 Not collective 8234 8235 Input Parameters: 8236 + dmRow - The `DM` for the row fields 8237 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8238 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8239 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8240 . dmCol - The `DM` for the column fields 8241 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8242 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8243 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8244 . A - The matrix 8245 . point - The point in the `DM` 8246 . values - The array of values 8247 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8248 8249 Level: intermediate 8250 8251 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8252 @*/ 8253 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) 8254 { 8255 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8256 PetscInt *indicesRow, *indicesCol; 8257 PetscInt numIndicesRow, numIndicesCol; 8258 const PetscScalar *valuesOrig = values; 8259 PetscErrorCode ierr; 8260 8261 PetscFunctionBegin; 8262 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8263 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8264 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8265 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8266 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8267 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8268 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8269 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8270 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8271 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8272 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8273 8274 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8275 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8276 8277 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8278 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8279 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 8280 if (ierr) { 8281 PetscMPIInt rank; 8282 8283 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8284 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8285 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8286 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8287 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 8288 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8289 } 8290 8291 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8292 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8293 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8294 PetscFunctionReturn(PETSC_SUCCESS); 8295 } 8296 8297 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8298 { 8299 DM_Plex *mesh = (DM_Plex *)dmf->data; 8300 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8301 PetscInt *cpoints = NULL; 8302 PetscInt *findices, *cindices; 8303 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8304 PetscInt foffsets[32], coffsets[32]; 8305 DMPolytopeType ct; 8306 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8307 PetscErrorCode ierr; 8308 8309 PetscFunctionBegin; 8310 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8311 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8312 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8313 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8314 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8315 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8316 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8317 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8318 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8319 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8320 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8321 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8322 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8323 PetscCall(PetscArrayzero(foffsets, 32)); 8324 PetscCall(PetscArrayzero(coffsets, 32)); 8325 /* Column indices */ 8326 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8327 maxFPoints = numCPoints; 8328 /* Compress out points not in the section */ 8329 /* TODO: Squeeze out points with 0 dof as well */ 8330 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8331 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8332 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8333 cpoints[q * 2] = cpoints[p]; 8334 cpoints[q * 2 + 1] = cpoints[p + 1]; 8335 ++q; 8336 } 8337 } 8338 numCPoints = q; 8339 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8340 PetscInt fdof; 8341 8342 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8343 if (!dof) continue; 8344 for (f = 0; f < numFields; ++f) { 8345 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8346 coffsets[f + 1] += fdof; 8347 } 8348 numCIndices += dof; 8349 } 8350 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8351 /* Row indices */ 8352 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8353 { 8354 DMPlexTransform tr; 8355 DMPolytopeType *rct; 8356 PetscInt *rsize, *rcone, *rornt, Nt; 8357 8358 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8359 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8360 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8361 numSubcells = rsize[Nt - 1]; 8362 PetscCall(DMPlexTransformDestroy(&tr)); 8363 } 8364 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8365 for (r = 0, q = 0; r < numSubcells; ++r) { 8366 /* TODO Map from coarse to fine cells */ 8367 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8368 /* Compress out points not in the section */ 8369 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8370 for (p = 0; p < numFPoints * 2; p += 2) { 8371 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8372 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8373 if (!dof) continue; 8374 for (s = 0; s < q; ++s) 8375 if (fpoints[p] == ftotpoints[s * 2]) break; 8376 if (s < q) continue; 8377 ftotpoints[q * 2] = fpoints[p]; 8378 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8379 ++q; 8380 } 8381 } 8382 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8383 } 8384 numFPoints = q; 8385 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8386 PetscInt fdof; 8387 8388 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8389 if (!dof) continue; 8390 for (f = 0; f < numFields; ++f) { 8391 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8392 foffsets[f + 1] += fdof; 8393 } 8394 numFIndices += dof; 8395 } 8396 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8397 8398 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8399 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8400 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8401 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8402 if (numFields) { 8403 const PetscInt **permsF[32] = {NULL}; 8404 const PetscInt **permsC[32] = {NULL}; 8405 8406 for (f = 0; f < numFields; f++) { 8407 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8408 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8409 } 8410 for (p = 0; p < numFPoints; p++) { 8411 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8412 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8413 } 8414 for (p = 0; p < numCPoints; p++) { 8415 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8416 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8417 } 8418 for (f = 0; f < numFields; f++) { 8419 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8420 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8421 } 8422 } else { 8423 const PetscInt **permsF = NULL; 8424 const PetscInt **permsC = NULL; 8425 8426 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8427 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8428 for (p = 0, off = 0; p < numFPoints; p++) { 8429 const PetscInt *perm = permsF ? permsF[p] : NULL; 8430 8431 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8432 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8433 } 8434 for (p = 0, off = 0; p < numCPoints; p++) { 8435 const PetscInt *perm = permsC ? permsC[p] : NULL; 8436 8437 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8438 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8439 } 8440 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8441 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8442 } 8443 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8444 /* TODO: flips */ 8445 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8446 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8447 if (ierr) { 8448 PetscMPIInt rank; 8449 8450 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8451 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8452 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8453 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8454 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8455 } 8456 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8457 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8458 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8459 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8460 PetscFunctionReturn(PETSC_SUCCESS); 8461 } 8462 8463 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8464 { 8465 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8466 PetscInt *cpoints = NULL; 8467 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8468 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8469 DMPolytopeType ct; 8470 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8471 8472 PetscFunctionBegin; 8473 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8474 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8475 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8476 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8477 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8478 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8479 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8480 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8481 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8482 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8483 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8484 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8485 /* Column indices */ 8486 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8487 maxFPoints = numCPoints; 8488 /* Compress out points not in the section */ 8489 /* TODO: Squeeze out points with 0 dof as well */ 8490 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8491 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8492 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8493 cpoints[q * 2] = cpoints[p]; 8494 cpoints[q * 2 + 1] = cpoints[p + 1]; 8495 ++q; 8496 } 8497 } 8498 numCPoints = q; 8499 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8500 PetscInt fdof; 8501 8502 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8503 if (!dof) continue; 8504 for (f = 0; f < numFields; ++f) { 8505 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8506 coffsets[f + 1] += fdof; 8507 } 8508 numCIndices += dof; 8509 } 8510 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8511 /* Row indices */ 8512 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8513 { 8514 DMPlexTransform tr; 8515 DMPolytopeType *rct; 8516 PetscInt *rsize, *rcone, *rornt, Nt; 8517 8518 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8519 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8520 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8521 numSubcells = rsize[Nt - 1]; 8522 PetscCall(DMPlexTransformDestroy(&tr)); 8523 } 8524 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8525 for (r = 0, q = 0; r < numSubcells; ++r) { 8526 /* TODO Map from coarse to fine cells */ 8527 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8528 /* Compress out points not in the section */ 8529 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8530 for (p = 0; p < numFPoints * 2; p += 2) { 8531 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8532 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8533 if (!dof) continue; 8534 for (s = 0; s < q; ++s) 8535 if (fpoints[p] == ftotpoints[s * 2]) break; 8536 if (s < q) continue; 8537 ftotpoints[q * 2] = fpoints[p]; 8538 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8539 ++q; 8540 } 8541 } 8542 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8543 } 8544 numFPoints = q; 8545 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8546 PetscInt fdof; 8547 8548 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8549 if (!dof) continue; 8550 for (f = 0; f < numFields; ++f) { 8551 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8552 foffsets[f + 1] += fdof; 8553 } 8554 numFIndices += dof; 8555 } 8556 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8557 8558 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8559 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8560 if (numFields) { 8561 const PetscInt **permsF[32] = {NULL}; 8562 const PetscInt **permsC[32] = {NULL}; 8563 8564 for (f = 0; f < numFields; f++) { 8565 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8566 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8567 } 8568 for (p = 0; p < numFPoints; p++) { 8569 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8570 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8571 } 8572 for (p = 0; p < numCPoints; p++) { 8573 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8574 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8575 } 8576 for (f = 0; f < numFields; f++) { 8577 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8578 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8579 } 8580 } else { 8581 const PetscInt **permsF = NULL; 8582 const PetscInt **permsC = NULL; 8583 8584 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8585 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8586 for (p = 0, off = 0; p < numFPoints; p++) { 8587 const PetscInt *perm = permsF ? permsF[p] : NULL; 8588 8589 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8590 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8591 } 8592 for (p = 0, off = 0; p < numCPoints; p++) { 8593 const PetscInt *perm = permsC ? permsC[p] : NULL; 8594 8595 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8596 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8597 } 8598 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8599 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8600 } 8601 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8602 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8603 PetscFunctionReturn(PETSC_SUCCESS); 8604 } 8605 8606 /*@C 8607 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8608 8609 Input Parameter: 8610 . dm - The `DMPLEX` object 8611 8612 Output Parameter: 8613 . cellHeight - The height of a cell 8614 8615 Level: developer 8616 8617 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8618 @*/ 8619 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8620 { 8621 DM_Plex *mesh = (DM_Plex *)dm->data; 8622 8623 PetscFunctionBegin; 8624 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8625 PetscAssertPointer(cellHeight, 2); 8626 *cellHeight = mesh->vtkCellHeight; 8627 PetscFunctionReturn(PETSC_SUCCESS); 8628 } 8629 8630 /*@C 8631 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8632 8633 Input Parameters: 8634 + dm - The `DMPLEX` object 8635 - cellHeight - The height of a cell 8636 8637 Level: developer 8638 8639 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8640 @*/ 8641 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8642 { 8643 DM_Plex *mesh = (DM_Plex *)dm->data; 8644 8645 PetscFunctionBegin; 8646 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8647 mesh->vtkCellHeight = cellHeight; 8648 PetscFunctionReturn(PETSC_SUCCESS); 8649 } 8650 8651 /*@ 8652 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8653 8654 Input Parameters: 8655 + dm - The `DMPLEX` object 8656 - ct - The `DMPolytopeType` of the cell 8657 8658 Output Parameters: 8659 + start - The first cell of this type, or `NULL` 8660 - end - The upper bound on this celltype, or `NULL` 8661 8662 Level: advanced 8663 8664 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8665 @*/ 8666 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8667 { 8668 DM_Plex *mesh = (DM_Plex *)dm->data; 8669 DMLabel label; 8670 PetscInt pStart, pEnd; 8671 8672 PetscFunctionBegin; 8673 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8674 if (start) { 8675 PetscAssertPointer(start, 3); 8676 *start = 0; 8677 } 8678 if (end) { 8679 PetscAssertPointer(end, 4); 8680 *end = 0; 8681 } 8682 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8683 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8684 if (mesh->tr) { 8685 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8686 } else { 8687 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8688 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8689 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8690 } 8691 PetscFunctionReturn(PETSC_SUCCESS); 8692 } 8693 8694 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8695 { 8696 PetscSection section, globalSection; 8697 PetscInt *numbers, p; 8698 8699 PetscFunctionBegin; 8700 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8701 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8702 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8703 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8704 PetscCall(PetscSectionSetUp(section)); 8705 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8706 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8707 for (p = pStart; p < pEnd; ++p) { 8708 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8709 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8710 else numbers[p - pStart] += shift; 8711 } 8712 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8713 if (globalSize) { 8714 PetscLayout layout; 8715 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8716 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8717 PetscCall(PetscLayoutDestroy(&layout)); 8718 } 8719 PetscCall(PetscSectionDestroy(§ion)); 8720 PetscCall(PetscSectionDestroy(&globalSection)); 8721 PetscFunctionReturn(PETSC_SUCCESS); 8722 } 8723 8724 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8725 { 8726 PetscInt cellHeight, cStart, cEnd; 8727 8728 PetscFunctionBegin; 8729 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8730 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8731 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8732 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8733 PetscFunctionReturn(PETSC_SUCCESS); 8734 } 8735 8736 /*@ 8737 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8738 8739 Input Parameter: 8740 . dm - The `DMPLEX` object 8741 8742 Output Parameter: 8743 . globalCellNumbers - Global cell numbers for all cells on this process 8744 8745 Level: developer 8746 8747 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8748 @*/ 8749 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8750 { 8751 DM_Plex *mesh = (DM_Plex *)dm->data; 8752 8753 PetscFunctionBegin; 8754 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8755 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8756 *globalCellNumbers = mesh->globalCellNumbers; 8757 PetscFunctionReturn(PETSC_SUCCESS); 8758 } 8759 8760 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8761 { 8762 PetscInt vStart, vEnd; 8763 8764 PetscFunctionBegin; 8765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8766 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8767 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8768 PetscFunctionReturn(PETSC_SUCCESS); 8769 } 8770 8771 /*@ 8772 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8773 8774 Input Parameter: 8775 . dm - The `DMPLEX` object 8776 8777 Output Parameter: 8778 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8779 8780 Level: developer 8781 8782 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8783 @*/ 8784 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8785 { 8786 DM_Plex *mesh = (DM_Plex *)dm->data; 8787 8788 PetscFunctionBegin; 8789 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8790 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8791 *globalVertexNumbers = mesh->globalVertexNumbers; 8792 PetscFunctionReturn(PETSC_SUCCESS); 8793 } 8794 8795 /*@ 8796 DMPlexCreatePointNumbering - Create a global numbering for all points. 8797 8798 Collective 8799 8800 Input Parameter: 8801 . dm - The `DMPLEX` object 8802 8803 Output Parameter: 8804 . globalPointNumbers - Global numbers for all points on this process 8805 8806 Level: developer 8807 8808 Notes: 8809 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8810 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8811 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8812 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8813 8814 The partitioned mesh is 8815 ``` 8816 (2)--0--(3)--1--(4) (1)--0--(2) 8817 ``` 8818 and its global numbering is 8819 ``` 8820 (3)--0--(4)--1--(5)--2--(6) 8821 ``` 8822 Then the global numbering is provided as 8823 ``` 8824 [0] Number of indices in set 5 8825 [0] 0 0 8826 [0] 1 1 8827 [0] 2 3 8828 [0] 3 4 8829 [0] 4 -6 8830 [1] Number of indices in set 3 8831 [1] 0 2 8832 [1] 1 5 8833 [1] 2 6 8834 ``` 8835 8836 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8837 @*/ 8838 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8839 { 8840 IS nums[4]; 8841 PetscInt depths[4], gdepths[4], starts[4]; 8842 PetscInt depth, d, shift = 0; 8843 PetscBool empty = PETSC_FALSE; 8844 8845 PetscFunctionBegin; 8846 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8847 PetscCall(DMPlexGetDepth(dm, &depth)); 8848 // For unstratified meshes use dim instead of depth 8849 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8850 // If any stratum is empty, we must mark all empty 8851 for (d = 0; d <= depth; ++d) { 8852 PetscInt end; 8853 8854 depths[d] = depth - d; 8855 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8856 if (!(starts[d] - end)) empty = PETSC_TRUE; 8857 } 8858 if (empty) 8859 for (d = 0; d <= depth; ++d) { 8860 depths[d] = -1; 8861 starts[d] = -1; 8862 } 8863 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8864 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8865 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]); 8866 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8867 for (d = 0; d <= depth; ++d) { 8868 PetscInt pStart, pEnd, gsize; 8869 8870 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8871 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8872 shift += gsize; 8873 } 8874 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8875 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8876 PetscFunctionReturn(PETSC_SUCCESS); 8877 } 8878 8879 /*@ 8880 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8881 8882 Input Parameter: 8883 . dm - The `DMPLEX` object 8884 8885 Output Parameter: 8886 . ranks - The rank field 8887 8888 Options Database Key: 8889 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8890 8891 Level: intermediate 8892 8893 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8894 @*/ 8895 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8896 { 8897 DM rdm; 8898 PetscFE fe; 8899 PetscScalar *r; 8900 PetscMPIInt rank; 8901 DMPolytopeType ct; 8902 PetscInt dim, cStart, cEnd, c; 8903 PetscBool simplex; 8904 8905 PetscFunctionBeginUser; 8906 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8907 PetscAssertPointer(ranks, 2); 8908 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8909 PetscCall(DMClone(dm, &rdm)); 8910 PetscCall(DMGetDimension(rdm, &dim)); 8911 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8912 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8913 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8914 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8915 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8916 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8917 PetscCall(PetscFEDestroy(&fe)); 8918 PetscCall(DMCreateDS(rdm)); 8919 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8920 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8921 PetscCall(VecGetArray(*ranks, &r)); 8922 for (c = cStart; c < cEnd; ++c) { 8923 PetscScalar *lr; 8924 8925 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8926 if (lr) *lr = rank; 8927 } 8928 PetscCall(VecRestoreArray(*ranks, &r)); 8929 PetscCall(DMDestroy(&rdm)); 8930 PetscFunctionReturn(PETSC_SUCCESS); 8931 } 8932 8933 /*@ 8934 DMPlexCreateLabelField - Create a field whose value is the label value for that point 8935 8936 Input Parameters: 8937 + dm - The `DMPLEX` 8938 - label - The `DMLabel` 8939 8940 Output Parameter: 8941 . val - The label value field 8942 8943 Options Database Key: 8944 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8945 8946 Level: intermediate 8947 8948 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8949 @*/ 8950 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8951 { 8952 DM rdm, plex; 8953 Vec lval; 8954 PetscSection section; 8955 PetscFE fe; 8956 PetscScalar *v; 8957 PetscInt dim, pStart, pEnd, p, cStart; 8958 DMPolytopeType ct; 8959 char name[PETSC_MAX_PATH_LEN]; 8960 const char *lname, *prefix; 8961 8962 PetscFunctionBeginUser; 8963 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8964 PetscAssertPointer(label, 2); 8965 PetscAssertPointer(val, 3); 8966 PetscCall(DMClone(dm, &rdm)); 8967 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 8968 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 8969 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 8970 PetscCall(DMDestroy(&plex)); 8971 PetscCall(DMGetDimension(rdm, &dim)); 8972 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 8973 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 8974 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 8975 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 8976 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 8977 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8978 PetscCall(PetscFEDestroy(&fe)); 8979 PetscCall(DMCreateDS(rdm)); 8980 PetscCall(DMCreateGlobalVector(rdm, val)); 8981 PetscCall(DMCreateLocalVector(rdm, &lval)); 8982 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 8983 PetscCall(DMGetLocalSection(rdm, §ion)); 8984 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 8985 PetscCall(VecGetArray(lval, &v)); 8986 for (p = pStart; p < pEnd; ++p) { 8987 PetscInt cval, dof, off; 8988 8989 PetscCall(PetscSectionGetDof(section, p, &dof)); 8990 if (!dof) continue; 8991 PetscCall(DMLabelGetValue(label, p, &cval)); 8992 PetscCall(PetscSectionGetOffset(section, p, &off)); 8993 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 8994 } 8995 PetscCall(VecRestoreArray(lval, &v)); 8996 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 8997 PetscCall(VecDestroy(&lval)); 8998 PetscCall(DMDestroy(&rdm)); 8999 PetscFunctionReturn(PETSC_SUCCESS); 9000 } 9001 9002 /*@ 9003 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9004 9005 Input Parameter: 9006 . dm - The `DMPLEX` object 9007 9008 Level: developer 9009 9010 Notes: 9011 This is a useful diagnostic when creating meshes programmatically. 9012 9013 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9014 9015 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9016 @*/ 9017 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9018 { 9019 PetscSection coneSection, supportSection; 9020 const PetscInt *cone, *support; 9021 PetscInt coneSize, c, supportSize, s; 9022 PetscInt pStart, pEnd, p, pp, csize, ssize; 9023 PetscBool storagecheck = PETSC_TRUE; 9024 9025 PetscFunctionBegin; 9026 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9027 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9028 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9029 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9030 /* Check that point p is found in the support of its cone points, and vice versa */ 9031 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9032 for (p = pStart; p < pEnd; ++p) { 9033 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9034 PetscCall(DMPlexGetCone(dm, p, &cone)); 9035 for (c = 0; c < coneSize; ++c) { 9036 PetscBool dup = PETSC_FALSE; 9037 PetscInt d; 9038 for (d = c - 1; d >= 0; --d) { 9039 if (cone[c] == cone[d]) { 9040 dup = PETSC_TRUE; 9041 break; 9042 } 9043 } 9044 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9045 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9046 for (s = 0; s < supportSize; ++s) { 9047 if (support[s] == p) break; 9048 } 9049 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9050 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9051 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9052 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9053 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9054 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9055 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9056 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]); 9057 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9058 } 9059 } 9060 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9061 if (p != pp) { 9062 storagecheck = PETSC_FALSE; 9063 continue; 9064 } 9065 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9066 PetscCall(DMPlexGetSupport(dm, p, &support)); 9067 for (s = 0; s < supportSize; ++s) { 9068 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9069 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9070 for (c = 0; c < coneSize; ++c) { 9071 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9072 if (cone[c] != pp) { 9073 c = 0; 9074 break; 9075 } 9076 if (cone[c] == p) break; 9077 } 9078 if (c >= coneSize) { 9079 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9080 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9081 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9082 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9083 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9084 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9085 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9086 } 9087 } 9088 } 9089 if (storagecheck) { 9090 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9091 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9092 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9093 } 9094 PetscFunctionReturn(PETSC_SUCCESS); 9095 } 9096 9097 /* 9098 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. 9099 */ 9100 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9101 { 9102 DMPolytopeType cct; 9103 PetscInt ptpoints[4]; 9104 const PetscInt *cone, *ccone, *ptcone; 9105 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9106 9107 PetscFunctionBegin; 9108 *unsplit = 0; 9109 switch (ct) { 9110 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9111 ptpoints[npt++] = c; 9112 break; 9113 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9114 PetscCall(DMPlexGetCone(dm, c, &cone)); 9115 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9116 for (cp = 0; cp < coneSize; ++cp) { 9117 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9118 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9119 } 9120 break; 9121 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9122 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9123 PetscCall(DMPlexGetCone(dm, c, &cone)); 9124 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9125 for (cp = 0; cp < coneSize; ++cp) { 9126 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9127 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9128 for (ccp = 0; ccp < cconeSize; ++ccp) { 9129 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9130 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9131 PetscInt p; 9132 for (p = 0; p < npt; ++p) 9133 if (ptpoints[p] == ccone[ccp]) break; 9134 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9135 } 9136 } 9137 } 9138 break; 9139 default: 9140 break; 9141 } 9142 for (pt = 0; pt < npt; ++pt) { 9143 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9144 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9145 } 9146 PetscFunctionReturn(PETSC_SUCCESS); 9147 } 9148 9149 /*@ 9150 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9151 9152 Input Parameters: 9153 + dm - The `DMPLEX` object 9154 - cellHeight - Normally 0 9155 9156 Level: developer 9157 9158 Notes: 9159 This is a useful diagnostic when creating meshes programmatically. 9160 Currently applicable only to homogeneous simplex or tensor meshes. 9161 9162 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9163 9164 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9165 @*/ 9166 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9167 { 9168 DMPlexInterpolatedFlag interp; 9169 DMPolytopeType ct; 9170 PetscInt vStart, vEnd, cStart, cEnd, c; 9171 9172 PetscFunctionBegin; 9173 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9174 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9175 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9176 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9177 for (c = cStart; c < cEnd; ++c) { 9178 PetscInt *closure = NULL; 9179 PetscInt coneSize, closureSize, cl, Nv = 0; 9180 9181 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9182 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9183 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9184 if (interp == DMPLEX_INTERPOLATED_FULL) { 9185 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9186 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)); 9187 } 9188 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9189 for (cl = 0; cl < closureSize * 2; cl += 2) { 9190 const PetscInt p = closure[cl]; 9191 if ((p >= vStart) && (p < vEnd)) ++Nv; 9192 } 9193 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9194 /* Special Case: Tensor faces with identified vertices */ 9195 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9196 PetscInt unsplit; 9197 9198 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9199 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9200 } 9201 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)); 9202 } 9203 PetscFunctionReturn(PETSC_SUCCESS); 9204 } 9205 9206 /*@ 9207 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9208 9209 Collective 9210 9211 Input Parameters: 9212 + dm - The `DMPLEX` object 9213 - cellHeight - Normally 0 9214 9215 Level: developer 9216 9217 Notes: 9218 This is a useful diagnostic when creating meshes programmatically. 9219 This routine is only relevant for meshes that are fully interpolated across all ranks. 9220 It will error out if a partially interpolated mesh is given on some rank. 9221 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9222 9223 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9224 9225 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9226 @*/ 9227 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9228 { 9229 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9230 DMPlexInterpolatedFlag interpEnum; 9231 9232 PetscFunctionBegin; 9233 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9234 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9235 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9236 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9237 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9238 PetscFunctionReturn(PETSC_SUCCESS); 9239 } 9240 9241 PetscCall(DMGetDimension(dm, &dim)); 9242 PetscCall(DMPlexGetDepth(dm, &depth)); 9243 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9244 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9245 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9246 for (c = cStart; c < cEnd; ++c) { 9247 const PetscInt *cone, *ornt, *faceSizes, *faces; 9248 const DMPolytopeType *faceTypes; 9249 DMPolytopeType ct; 9250 PetscInt numFaces, coneSize, f; 9251 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9252 9253 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9254 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9255 if (unsplit) continue; 9256 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9257 PetscCall(DMPlexGetCone(dm, c, &cone)); 9258 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9259 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9260 for (cl = 0; cl < closureSize * 2; cl += 2) { 9261 const PetscInt p = closure[cl]; 9262 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9263 } 9264 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9265 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); 9266 for (f = 0; f < numFaces; ++f) { 9267 DMPolytopeType fct; 9268 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9269 9270 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9271 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9272 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9273 const PetscInt p = fclosure[cl]; 9274 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9275 } 9276 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]); 9277 for (v = 0; v < fnumCorners; ++v) { 9278 if (fclosure[v] != faces[fOff + v]) { 9279 PetscInt v1; 9280 9281 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9282 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9283 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9284 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9285 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9286 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]); 9287 } 9288 } 9289 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9290 fOff += faceSizes[f]; 9291 } 9292 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9293 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9294 } 9295 } 9296 PetscFunctionReturn(PETSC_SUCCESS); 9297 } 9298 9299 /*@ 9300 DMPlexCheckGeometry - Check the geometry of mesh cells 9301 9302 Input Parameter: 9303 . dm - The `DMPLEX` object 9304 9305 Level: developer 9306 9307 Notes: 9308 This is a useful diagnostic when creating meshes programmatically. 9309 9310 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9311 9312 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9313 @*/ 9314 PetscErrorCode DMPlexCheckGeometry(DM dm) 9315 { 9316 Vec coordinates; 9317 PetscReal detJ, J[9], refVol = 1.0; 9318 PetscReal vol; 9319 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9320 9321 PetscFunctionBegin; 9322 PetscCall(DMGetDimension(dm, &dim)); 9323 PetscCall(DMGetCoordinateDim(dm, &dE)); 9324 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9325 PetscCall(DMPlexGetDepth(dm, &depth)); 9326 for (d = 0; d < dim; ++d) refVol *= 2.0; 9327 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9328 /* Make sure local coordinates are created, because that step is collective */ 9329 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9330 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9331 for (c = cStart; c < cEnd; ++c) { 9332 DMPolytopeType ct; 9333 PetscInt unsplit; 9334 PetscBool ignoreZeroVol = PETSC_FALSE; 9335 9336 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9337 switch (ct) { 9338 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9339 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9340 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9341 ignoreZeroVol = PETSC_TRUE; 9342 break; 9343 default: 9344 break; 9345 } 9346 switch (ct) { 9347 case DM_POLYTOPE_TRI_PRISM: 9348 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9349 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9350 case DM_POLYTOPE_PYRAMID: 9351 continue; 9352 default: 9353 break; 9354 } 9355 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9356 if (unsplit) continue; 9357 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9358 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); 9359 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9360 /* This should work with periodicity since DG coordinates should be used */ 9361 if (depth > 1) { 9362 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9363 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); 9364 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9365 } 9366 } 9367 PetscFunctionReturn(PETSC_SUCCESS); 9368 } 9369 9370 /*@ 9371 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9372 9373 Collective 9374 9375 Input Parameters: 9376 + dm - The `DMPLEX` object 9377 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9378 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9379 9380 Level: developer 9381 9382 Notes: 9383 This is mainly intended for debugging/testing purposes. 9384 9385 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9386 9387 Extra roots can come from periodic cuts, where additional points appear on the boundary 9388 9389 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9390 @*/ 9391 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9392 { 9393 PetscInt l, nleaves, nroots, overlap; 9394 const PetscInt *locals; 9395 const PetscSFNode *remotes; 9396 PetscBool distributed; 9397 MPI_Comm comm; 9398 PetscMPIInt rank; 9399 9400 PetscFunctionBegin; 9401 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9402 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9403 else pointSF = dm->sf; 9404 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9405 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9406 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9407 { 9408 PetscMPIInt mpiFlag; 9409 9410 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9411 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9412 } 9413 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9414 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9415 if (!distributed) { 9416 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); 9417 PetscFunctionReturn(PETSC_SUCCESS); 9418 } 9419 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); 9420 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9421 9422 /* Check SF graph is compatible with DMPlex chart */ 9423 { 9424 PetscInt pStart, pEnd, maxLeaf; 9425 9426 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9427 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9428 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9429 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9430 } 9431 9432 /* Check Point SF has no local points referenced */ 9433 for (l = 0; l < nleaves; l++) { 9434 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); 9435 } 9436 9437 /* Check there are no cells in interface */ 9438 if (!overlap) { 9439 PetscInt cellHeight, cStart, cEnd; 9440 9441 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9442 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9443 for (l = 0; l < nleaves; ++l) { 9444 const PetscInt point = locals ? locals[l] : l; 9445 9446 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9447 } 9448 } 9449 9450 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9451 { 9452 const PetscInt *rootdegree; 9453 9454 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9455 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9456 for (l = 0; l < nleaves; ++l) { 9457 const PetscInt point = locals ? locals[l] : l; 9458 const PetscInt *cone; 9459 PetscInt coneSize, c, idx; 9460 9461 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9462 PetscCall(DMPlexGetCone(dm, point, &cone)); 9463 for (c = 0; c < coneSize; ++c) { 9464 if (!rootdegree[cone[c]]) { 9465 if (locals) { 9466 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9467 } else { 9468 idx = (cone[c] < nleaves) ? cone[c] : -1; 9469 } 9470 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9471 } 9472 } 9473 } 9474 } 9475 PetscFunctionReturn(PETSC_SUCCESS); 9476 } 9477 9478 /*@ 9479 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9480 9481 Input Parameter: 9482 . dm - The `DMPLEX` object 9483 9484 Level: developer 9485 9486 Notes: 9487 This is a useful diagnostic when creating meshes programmatically. 9488 9489 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9490 9491 Currently does not include `DMPlexCheckCellShape()`. 9492 9493 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9494 @*/ 9495 PetscErrorCode DMPlexCheck(DM dm) 9496 { 9497 PetscInt cellHeight; 9498 9499 PetscFunctionBegin; 9500 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9501 PetscCall(DMPlexCheckSymmetry(dm)); 9502 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9503 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9504 PetscCall(DMPlexCheckGeometry(dm)); 9505 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9506 PetscCall(DMPlexCheckInterfaceCones(dm)); 9507 PetscFunctionReturn(PETSC_SUCCESS); 9508 } 9509 9510 typedef struct cell_stats { 9511 PetscReal min, max, sum, squaresum; 9512 PetscInt count; 9513 } cell_stats_t; 9514 9515 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9516 { 9517 PetscInt i, N = *len; 9518 9519 for (i = 0; i < N; i++) { 9520 cell_stats_t *A = (cell_stats_t *)a; 9521 cell_stats_t *B = (cell_stats_t *)b; 9522 9523 B->min = PetscMin(A->min, B->min); 9524 B->max = PetscMax(A->max, B->max); 9525 B->sum += A->sum; 9526 B->squaresum += A->squaresum; 9527 B->count += A->count; 9528 } 9529 } 9530 9531 /*@ 9532 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9533 9534 Collective 9535 9536 Input Parameters: 9537 + dm - The `DMPLEX` object 9538 . output - If true, statistics will be displayed on `stdout` 9539 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9540 9541 Level: developer 9542 9543 Notes: 9544 This is mainly intended for debugging/testing purposes. 9545 9546 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9547 9548 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9549 @*/ 9550 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9551 { 9552 DM dmCoarse; 9553 cell_stats_t stats, globalStats; 9554 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9555 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9556 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9557 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9558 PetscMPIInt rank, size; 9559 9560 PetscFunctionBegin; 9561 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9562 stats.min = PETSC_MAX_REAL; 9563 stats.max = PETSC_MIN_REAL; 9564 stats.sum = stats.squaresum = 0.; 9565 stats.count = 0; 9566 9567 PetscCallMPI(MPI_Comm_size(comm, &size)); 9568 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9569 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9570 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9571 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9572 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9573 for (c = cStart; c < cEnd; c++) { 9574 PetscInt i; 9575 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9576 9577 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9578 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9579 for (i = 0; i < PetscSqr(cdim); ++i) { 9580 frobJ += J[i] * J[i]; 9581 frobInvJ += invJ[i] * invJ[i]; 9582 } 9583 cond2 = frobJ * frobInvJ; 9584 cond = PetscSqrtReal(cond2); 9585 9586 stats.min = PetscMin(stats.min, cond); 9587 stats.max = PetscMax(stats.max, cond); 9588 stats.sum += cond; 9589 stats.squaresum += cond2; 9590 stats.count++; 9591 if (output && cond > limit) { 9592 PetscSection coordSection; 9593 Vec coordsLocal; 9594 PetscScalar *coords = NULL; 9595 PetscInt Nv, d, clSize, cl, *closure = NULL; 9596 9597 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9598 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9599 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9600 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9601 for (i = 0; i < Nv / cdim; ++i) { 9602 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9603 for (d = 0; d < cdim; ++d) { 9604 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9605 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9606 } 9607 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9608 } 9609 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9610 for (cl = 0; cl < clSize * 2; cl += 2) { 9611 const PetscInt edge = closure[cl]; 9612 9613 if ((edge >= eStart) && (edge < eEnd)) { 9614 PetscReal len; 9615 9616 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9617 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9618 } 9619 } 9620 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9621 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9622 } 9623 } 9624 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9625 9626 if (size > 1) { 9627 PetscMPIInt blockLengths[2] = {4, 1}; 9628 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9629 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9630 MPI_Op statReduce; 9631 9632 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9633 PetscCallMPI(MPI_Type_commit(&statType)); 9634 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9635 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9636 PetscCallMPI(MPI_Op_free(&statReduce)); 9637 PetscCallMPI(MPI_Type_free(&statType)); 9638 } else { 9639 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9640 } 9641 if (rank == 0) { 9642 count = globalStats.count; 9643 min = globalStats.min; 9644 max = globalStats.max; 9645 mean = globalStats.sum / globalStats.count; 9646 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9647 } 9648 9649 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)); 9650 PetscCall(PetscFree2(J, invJ)); 9651 9652 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9653 if (dmCoarse) { 9654 PetscBool isplex; 9655 9656 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9657 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9658 } 9659 PetscFunctionReturn(PETSC_SUCCESS); 9660 } 9661 9662 /*@ 9663 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9664 orthogonal quality below given tolerance. 9665 9666 Collective 9667 9668 Input Parameters: 9669 + dm - The `DMPLEX` object 9670 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9671 - atol - [0, 1] Absolute tolerance for tagging cells. 9672 9673 Output Parameters: 9674 + OrthQual - `Vec` containing orthogonal quality per cell 9675 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9676 9677 Options Database Keys: 9678 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9679 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9680 9681 Level: intermediate 9682 9683 Notes: 9684 Orthogonal quality is given by the following formula\: 9685 9686 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9687 9688 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 9689 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9690 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9691 calculating the cosine of the angle between these vectors. 9692 9693 Orthogonal quality ranges from 1 (best) to 0 (worst). 9694 9695 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9696 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9697 9698 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9699 9700 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9701 @*/ 9702 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9703 { 9704 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9705 PetscInt *idx; 9706 PetscScalar *oqVals; 9707 const PetscScalar *cellGeomArr, *faceGeomArr; 9708 PetscReal *ci, *fi, *Ai; 9709 MPI_Comm comm; 9710 Vec cellgeom, facegeom; 9711 DM dmFace, dmCell; 9712 IS glob; 9713 ISLocalToGlobalMapping ltog; 9714 PetscViewer vwr; 9715 9716 PetscFunctionBegin; 9717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9718 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9719 PetscAssertPointer(OrthQual, 4); 9720 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9721 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9722 PetscCall(DMGetDimension(dm, &nc)); 9723 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9724 { 9725 DMPlexInterpolatedFlag interpFlag; 9726 9727 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9728 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9729 PetscMPIInt rank; 9730 9731 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9732 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9733 } 9734 } 9735 if (OrthQualLabel) { 9736 PetscAssertPointer(OrthQualLabel, 5); 9737 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9738 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9739 } else { 9740 *OrthQualLabel = NULL; 9741 } 9742 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9743 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9744 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9745 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9746 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9747 PetscCall(VecCreate(comm, OrthQual)); 9748 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9749 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9750 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9751 PetscCall(VecSetUp(*OrthQual)); 9752 PetscCall(ISDestroy(&glob)); 9753 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9754 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9755 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9756 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9757 PetscCall(VecGetDM(cellgeom, &dmCell)); 9758 PetscCall(VecGetDM(facegeom, &dmFace)); 9759 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9760 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9761 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9762 PetscInt cellarr[2], *adj = NULL; 9763 PetscScalar *cArr, *fArr; 9764 PetscReal minvalc = 1.0, minvalf = 1.0; 9765 PetscFVCellGeom *cg; 9766 9767 idx[cellIter] = cell - cStart; 9768 cellarr[0] = cell; 9769 /* Make indexing into cellGeom easier */ 9770 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9771 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9772 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9773 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9774 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9775 PetscInt i; 9776 const PetscInt neigh = adj[cellneigh]; 9777 PetscReal normci = 0, normfi = 0, normai = 0; 9778 PetscFVCellGeom *cgneigh; 9779 PetscFVFaceGeom *fg; 9780 9781 /* Don't count ourselves in the neighbor list */ 9782 if (neigh == cell) continue; 9783 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9784 cellarr[1] = neigh; 9785 { 9786 PetscInt numcovpts; 9787 const PetscInt *covpts; 9788 9789 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9790 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9791 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9792 } 9793 9794 /* Compute c_i, f_i and their norms */ 9795 for (i = 0; i < nc; i++) { 9796 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9797 fi[i] = fg->centroid[i] - cg->centroid[i]; 9798 Ai[i] = fg->normal[i]; 9799 normci += PetscPowReal(ci[i], 2); 9800 normfi += PetscPowReal(fi[i], 2); 9801 normai += PetscPowReal(Ai[i], 2); 9802 } 9803 normci = PetscSqrtReal(normci); 9804 normfi = PetscSqrtReal(normfi); 9805 normai = PetscSqrtReal(normai); 9806 9807 /* Normalize and compute for each face-cell-normal pair */ 9808 for (i = 0; i < nc; i++) { 9809 ci[i] = ci[i] / normci; 9810 fi[i] = fi[i] / normfi; 9811 Ai[i] = Ai[i] / normai; 9812 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9813 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9814 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9815 } 9816 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9817 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9818 } 9819 PetscCall(PetscFree(adj)); 9820 PetscCall(PetscFree2(cArr, fArr)); 9821 /* Defer to cell if they're equal */ 9822 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9823 if (OrthQualLabel) { 9824 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9825 } 9826 } 9827 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9828 PetscCall(VecAssemblyBegin(*OrthQual)); 9829 PetscCall(VecAssemblyEnd(*OrthQual)); 9830 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9831 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9832 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9833 if (OrthQualLabel) { 9834 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9835 } 9836 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9837 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9838 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9839 PetscFunctionReturn(PETSC_SUCCESS); 9840 } 9841 9842 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9843 * interpolator construction */ 9844 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9845 { 9846 PetscSection section, newSection, gsection; 9847 PetscSF sf; 9848 PetscBool hasConstraints, ghasConstraints; 9849 9850 PetscFunctionBegin; 9851 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9852 PetscAssertPointer(odm, 2); 9853 PetscCall(DMGetLocalSection(dm, §ion)); 9854 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9855 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9856 if (!ghasConstraints) { 9857 PetscCall(PetscObjectReference((PetscObject)dm)); 9858 *odm = dm; 9859 PetscFunctionReturn(PETSC_SUCCESS); 9860 } 9861 PetscCall(DMClone(dm, odm)); 9862 PetscCall(DMCopyFields(dm, *odm)); 9863 PetscCall(DMGetLocalSection(*odm, &newSection)); 9864 PetscCall(DMGetPointSF(*odm, &sf)); 9865 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9866 PetscCall(DMSetGlobalSection(*odm, gsection)); 9867 PetscCall(PetscSectionDestroy(&gsection)); 9868 PetscFunctionReturn(PETSC_SUCCESS); 9869 } 9870 9871 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9872 { 9873 DM dmco, dmfo; 9874 Mat interpo; 9875 Vec rscale; 9876 Vec cglobalo, clocal; 9877 Vec fglobal, fglobalo, flocal; 9878 PetscBool regular; 9879 9880 PetscFunctionBegin; 9881 PetscCall(DMGetFullDM(dmc, &dmco)); 9882 PetscCall(DMGetFullDM(dmf, &dmfo)); 9883 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9884 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9885 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9886 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9887 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9888 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9889 PetscCall(VecSet(cglobalo, 0.)); 9890 PetscCall(VecSet(clocal, 0.)); 9891 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9892 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9893 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9894 PetscCall(VecSet(fglobal, 0.)); 9895 PetscCall(VecSet(fglobalo, 0.)); 9896 PetscCall(VecSet(flocal, 0.)); 9897 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9898 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9899 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9900 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9901 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9902 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9903 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9904 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9905 *shift = fglobal; 9906 PetscCall(VecDestroy(&flocal)); 9907 PetscCall(VecDestroy(&fglobalo)); 9908 PetscCall(VecDestroy(&clocal)); 9909 PetscCall(VecDestroy(&cglobalo)); 9910 PetscCall(VecDestroy(&rscale)); 9911 PetscCall(MatDestroy(&interpo)); 9912 PetscCall(DMDestroy(&dmfo)); 9913 PetscCall(DMDestroy(&dmco)); 9914 PetscFunctionReturn(PETSC_SUCCESS); 9915 } 9916 9917 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9918 { 9919 PetscObject shifto; 9920 Vec shift; 9921 9922 PetscFunctionBegin; 9923 if (!interp) { 9924 Vec rscale; 9925 9926 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9927 PetscCall(VecDestroy(&rscale)); 9928 } else { 9929 PetscCall(PetscObjectReference((PetscObject)interp)); 9930 } 9931 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9932 if (!shifto) { 9933 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9934 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9935 shifto = (PetscObject)shift; 9936 PetscCall(VecDestroy(&shift)); 9937 } 9938 shift = (Vec)shifto; 9939 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9940 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9941 PetscCall(MatDestroy(&interp)); 9942 PetscFunctionReturn(PETSC_SUCCESS); 9943 } 9944 9945 /* Pointwise interpolation 9946 Just code FEM for now 9947 u^f = I u^c 9948 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9949 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9950 I_{ij} = psi^f_i phi^c_j 9951 */ 9952 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9953 { 9954 PetscSection gsc, gsf; 9955 PetscInt m, n; 9956 void *ctx; 9957 DM cdm; 9958 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9959 9960 PetscFunctionBegin; 9961 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9962 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9963 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9964 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9965 9966 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9967 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9968 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9969 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9970 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9971 9972 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9973 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9974 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9975 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9976 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9977 if (scaling) { 9978 /* Use naive scaling */ 9979 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9980 } 9981 PetscFunctionReturn(PETSC_SUCCESS); 9982 } 9983 9984 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9985 { 9986 VecScatter ctx; 9987 9988 PetscFunctionBegin; 9989 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9990 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9991 PetscCall(VecScatterDestroy(&ctx)); 9992 PetscFunctionReturn(PETSC_SUCCESS); 9993 } 9994 9995 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[]) 9996 { 9997 const PetscInt Nc = uOff[1] - uOff[0]; 9998 PetscInt c; 9999 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10000 } 10001 10002 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 10003 { 10004 DM dmc; 10005 PetscDS ds; 10006 Vec ones, locmass; 10007 IS cellIS; 10008 PetscFormKey key; 10009 PetscInt depth; 10010 10011 PetscFunctionBegin; 10012 PetscCall(DMClone(dm, &dmc)); 10013 PetscCall(DMCopyDisc(dm, dmc)); 10014 PetscCall(DMGetDS(dmc, &ds)); 10015 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10016 PetscCall(DMCreateGlobalVector(dmc, mass)); 10017 PetscCall(DMGetLocalVector(dmc, &ones)); 10018 PetscCall(DMGetLocalVector(dmc, &locmass)); 10019 PetscCall(DMPlexGetDepth(dmc, &depth)); 10020 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10021 PetscCall(VecSet(locmass, 0.0)); 10022 PetscCall(VecSet(ones, 1.0)); 10023 key.label = NULL; 10024 key.value = 0; 10025 key.field = 0; 10026 key.part = 0; 10027 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10028 PetscCall(ISDestroy(&cellIS)); 10029 PetscCall(VecSet(*mass, 0.0)); 10030 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 10031 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 10032 PetscCall(DMRestoreLocalVector(dmc, &ones)); 10033 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 10034 PetscCall(DMDestroy(&dmc)); 10035 PetscFunctionReturn(PETSC_SUCCESS); 10036 } 10037 10038 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10039 { 10040 PetscSection gsc, gsf; 10041 PetscInt m, n; 10042 void *ctx; 10043 DM cdm; 10044 PetscBool regular; 10045 10046 PetscFunctionBegin; 10047 if (dmFine == dmCoarse) { 10048 DM dmc; 10049 PetscDS ds; 10050 PetscWeakForm wf; 10051 Vec u; 10052 IS cellIS; 10053 PetscFormKey key; 10054 PetscInt depth; 10055 10056 PetscCall(DMClone(dmFine, &dmc)); 10057 PetscCall(DMCopyDisc(dmFine, dmc)); 10058 PetscCall(DMGetDS(dmc, &ds)); 10059 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10060 PetscCall(PetscWeakFormClear(wf)); 10061 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10062 PetscCall(DMCreateMatrix(dmc, mass)); 10063 PetscCall(DMGetLocalVector(dmc, &u)); 10064 PetscCall(DMPlexGetDepth(dmc, &depth)); 10065 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10066 PetscCall(MatZeroEntries(*mass)); 10067 key.label = NULL; 10068 key.value = 0; 10069 key.field = 0; 10070 key.part = 0; 10071 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10072 PetscCall(ISDestroy(&cellIS)); 10073 PetscCall(DMRestoreLocalVector(dmc, &u)); 10074 PetscCall(DMDestroy(&dmc)); 10075 } else { 10076 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10077 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10078 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10079 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10080 10081 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10082 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10083 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10084 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10085 10086 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10087 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10088 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10089 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10090 } 10091 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10092 PetscFunctionReturn(PETSC_SUCCESS); 10093 } 10094 10095 /*@ 10096 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10097 10098 Input Parameter: 10099 . dm - The `DMPLEX` object 10100 10101 Output Parameter: 10102 . regular - The flag 10103 10104 Level: intermediate 10105 10106 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10107 @*/ 10108 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10109 { 10110 PetscFunctionBegin; 10111 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10112 PetscAssertPointer(regular, 2); 10113 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10114 PetscFunctionReturn(PETSC_SUCCESS); 10115 } 10116 10117 /*@ 10118 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10119 10120 Input Parameters: 10121 + dm - The `DMPLEX` object 10122 - regular - The flag 10123 10124 Level: intermediate 10125 10126 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10127 @*/ 10128 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10129 { 10130 PetscFunctionBegin; 10131 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10132 ((DM_Plex *)dm->data)->regularRefinement = regular; 10133 PetscFunctionReturn(PETSC_SUCCESS); 10134 } 10135 10136 /*@ 10137 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10138 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10139 10140 Not Collective 10141 10142 Input Parameter: 10143 . dm - The `DMPLEX` object 10144 10145 Output Parameters: 10146 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10147 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10148 10149 Level: intermediate 10150 10151 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10152 @*/ 10153 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10154 { 10155 DM_Plex *plex = (DM_Plex *)dm->data; 10156 10157 PetscFunctionBegin; 10158 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10159 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10160 if (anchorSection) *anchorSection = plex->anchorSection; 10161 if (anchorIS) *anchorIS = plex->anchorIS; 10162 PetscFunctionReturn(PETSC_SUCCESS); 10163 } 10164 10165 /*@ 10166 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10167 10168 Collective 10169 10170 Input Parameters: 10171 + dm - The `DMPLEX` object 10172 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10173 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10174 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10175 10176 Level: intermediate 10177 10178 Notes: 10179 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10180 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10181 combination of other points' degrees of freedom. 10182 10183 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10184 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10185 10186 The reference counts of `anchorSection` and `anchorIS` are incremented. 10187 10188 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10189 @*/ 10190 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10191 { 10192 DM_Plex *plex = (DM_Plex *)dm->data; 10193 PetscMPIInt result; 10194 10195 PetscFunctionBegin; 10196 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10197 if (anchorSection) { 10198 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10199 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10200 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10201 } 10202 if (anchorIS) { 10203 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10204 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10205 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10206 } 10207 10208 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10209 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10210 plex->anchorSection = anchorSection; 10211 10212 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10213 PetscCall(ISDestroy(&plex->anchorIS)); 10214 plex->anchorIS = anchorIS; 10215 10216 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10217 PetscInt size, a, pStart, pEnd; 10218 const PetscInt *anchors; 10219 10220 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10221 PetscCall(ISGetLocalSize(anchorIS, &size)); 10222 PetscCall(ISGetIndices(anchorIS, &anchors)); 10223 for (a = 0; a < size; a++) { 10224 PetscInt p; 10225 10226 p = anchors[a]; 10227 if (p >= pStart && p < pEnd) { 10228 PetscInt dof; 10229 10230 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10231 if (dof) { 10232 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10233 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10234 } 10235 } 10236 } 10237 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10238 } 10239 /* reset the generic constraints */ 10240 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10241 PetscFunctionReturn(PETSC_SUCCESS); 10242 } 10243 10244 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10245 { 10246 PetscSection anchorSection; 10247 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10248 10249 PetscFunctionBegin; 10250 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10251 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10252 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10253 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10254 if (numFields) { 10255 PetscInt f; 10256 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10257 10258 for (f = 0; f < numFields; f++) { 10259 PetscInt numComp; 10260 10261 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10262 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10263 } 10264 } 10265 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10266 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10267 pStart = PetscMax(pStart, sStart); 10268 pEnd = PetscMin(pEnd, sEnd); 10269 pEnd = PetscMax(pStart, pEnd); 10270 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10271 for (p = pStart; p < pEnd; p++) { 10272 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10273 if (dof) { 10274 PetscCall(PetscSectionGetDof(section, p, &dof)); 10275 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10276 for (f = 0; f < numFields; f++) { 10277 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10278 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10279 } 10280 } 10281 } 10282 PetscCall(PetscSectionSetUp(*cSec)); 10283 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10284 PetscFunctionReturn(PETSC_SUCCESS); 10285 } 10286 10287 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10288 { 10289 PetscSection aSec; 10290 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10291 const PetscInt *anchors; 10292 PetscInt numFields, f; 10293 IS aIS; 10294 MatType mtype; 10295 PetscBool iscuda, iskokkos; 10296 10297 PetscFunctionBegin; 10298 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10299 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10300 PetscCall(PetscSectionGetStorageSize(section, &n)); 10301 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10302 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10303 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10304 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10305 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10306 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10307 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10308 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10309 else mtype = MATSEQAIJ; 10310 PetscCall(MatSetType(*cMat, mtype)); 10311 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10312 PetscCall(ISGetIndices(aIS, &anchors)); 10313 /* cSec will be a subset of aSec and section */ 10314 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10315 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10316 PetscCall(PetscMalloc1(m + 1, &i)); 10317 i[0] = 0; 10318 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10319 for (p = pStart; p < pEnd; p++) { 10320 PetscInt rDof, rOff, r; 10321 10322 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10323 if (!rDof) continue; 10324 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10325 if (numFields) { 10326 for (f = 0; f < numFields; f++) { 10327 annz = 0; 10328 for (r = 0; r < rDof; r++) { 10329 a = anchors[rOff + r]; 10330 if (a < sStart || a >= sEnd) continue; 10331 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10332 annz += aDof; 10333 } 10334 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10335 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10336 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10337 } 10338 } else { 10339 annz = 0; 10340 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10341 for (q = 0; q < dof; q++) { 10342 a = anchors[rOff + q]; 10343 if (a < sStart || a >= sEnd) continue; 10344 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10345 annz += aDof; 10346 } 10347 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10348 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10349 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10350 } 10351 } 10352 nnz = i[m]; 10353 PetscCall(PetscMalloc1(nnz, &j)); 10354 offset = 0; 10355 for (p = pStart; p < pEnd; p++) { 10356 if (numFields) { 10357 for (f = 0; f < numFields; f++) { 10358 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10359 for (q = 0; q < dof; q++) { 10360 PetscInt rDof, rOff, r; 10361 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10362 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10363 for (r = 0; r < rDof; r++) { 10364 PetscInt s; 10365 10366 a = anchors[rOff + r]; 10367 if (a < sStart || a >= sEnd) continue; 10368 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10369 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10370 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10371 } 10372 } 10373 } 10374 } else { 10375 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10376 for (q = 0; q < dof; q++) { 10377 PetscInt rDof, rOff, r; 10378 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10379 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10380 for (r = 0; r < rDof; r++) { 10381 PetscInt s; 10382 10383 a = anchors[rOff + r]; 10384 if (a < sStart || a >= sEnd) continue; 10385 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10386 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10387 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10388 } 10389 } 10390 } 10391 } 10392 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10393 PetscCall(PetscFree(i)); 10394 PetscCall(PetscFree(j)); 10395 PetscCall(ISRestoreIndices(aIS, &anchors)); 10396 PetscFunctionReturn(PETSC_SUCCESS); 10397 } 10398 10399 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10400 { 10401 DM_Plex *plex = (DM_Plex *)dm->data; 10402 PetscSection anchorSection, section, cSec; 10403 Mat cMat; 10404 10405 PetscFunctionBegin; 10406 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10407 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10408 if (anchorSection) { 10409 PetscInt Nf; 10410 10411 PetscCall(DMGetLocalSection(dm, §ion)); 10412 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10413 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10414 PetscCall(DMGetNumFields(dm, &Nf)); 10415 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10416 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10417 PetscCall(PetscSectionDestroy(&cSec)); 10418 PetscCall(MatDestroy(&cMat)); 10419 } 10420 PetscFunctionReturn(PETSC_SUCCESS); 10421 } 10422 10423 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10424 { 10425 IS subis; 10426 PetscSection section, subsection; 10427 10428 PetscFunctionBegin; 10429 PetscCall(DMGetLocalSection(dm, §ion)); 10430 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10431 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10432 /* Create subdomain */ 10433 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10434 /* Create submodel */ 10435 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10436 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10437 PetscCall(DMSetLocalSection(*subdm, subsection)); 10438 PetscCall(PetscSectionDestroy(&subsection)); 10439 PetscCall(DMCopyDisc(dm, *subdm)); 10440 /* Create map from submodel to global model */ 10441 if (is) { 10442 PetscSection sectionGlobal, subsectionGlobal; 10443 IS spIS; 10444 const PetscInt *spmap; 10445 PetscInt *subIndices; 10446 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10447 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10448 10449 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10450 PetscCall(ISGetIndices(spIS, &spmap)); 10451 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10452 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10453 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10454 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10455 for (p = pStart; p < pEnd; ++p) { 10456 PetscInt gdof, pSubSize = 0; 10457 10458 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10459 if (gdof > 0) { 10460 for (f = 0; f < Nf; ++f) { 10461 PetscInt fdof, fcdof; 10462 10463 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10464 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10465 pSubSize += fdof - fcdof; 10466 } 10467 subSize += pSubSize; 10468 if (pSubSize) { 10469 if (bs < 0) { 10470 bs = pSubSize; 10471 } else if (bs != pSubSize) { 10472 /* Layout does not admit a pointwise block size */ 10473 bs = 1; 10474 } 10475 } 10476 } 10477 } 10478 /* Must have same blocksize on all procs (some might have no points) */ 10479 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10480 bsLocal[1] = bs; 10481 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10482 if (bsMinMax[0] != bsMinMax[1]) { 10483 bs = 1; 10484 } else { 10485 bs = bsMinMax[0]; 10486 } 10487 PetscCall(PetscMalloc1(subSize, &subIndices)); 10488 for (p = pStart; p < pEnd; ++p) { 10489 PetscInt gdof, goff; 10490 10491 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10492 if (gdof > 0) { 10493 const PetscInt point = spmap[p]; 10494 10495 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10496 for (f = 0; f < Nf; ++f) { 10497 PetscInt fdof, fcdof, fc, f2, poff = 0; 10498 10499 /* Can get rid of this loop by storing field information in the global section */ 10500 for (f2 = 0; f2 < f; ++f2) { 10501 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10502 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10503 poff += fdof - fcdof; 10504 } 10505 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10506 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10507 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10508 } 10509 } 10510 } 10511 PetscCall(ISRestoreIndices(spIS, &spmap)); 10512 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10513 if (bs > 1) { 10514 /* We need to check that the block size does not come from non-contiguous fields */ 10515 PetscInt i, j, set = 1; 10516 for (i = 0; i < subSize; i += bs) { 10517 for (j = 0; j < bs; ++j) { 10518 if (subIndices[i + j] != subIndices[i] + j) { 10519 set = 0; 10520 break; 10521 } 10522 } 10523 } 10524 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10525 } 10526 /* Attach nullspace */ 10527 for (f = 0; f < Nf; ++f) { 10528 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10529 if ((*subdm)->nullspaceConstructors[f]) break; 10530 } 10531 if (f < Nf) { 10532 MatNullSpace nullSpace; 10533 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10534 10535 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10536 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10537 } 10538 } 10539 PetscFunctionReturn(PETSC_SUCCESS); 10540 } 10541 10542 /*@ 10543 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10544 10545 Input Parameters: 10546 + dm - The `DM` 10547 - dummy - unused argument 10548 10549 Options Database Key: 10550 . -dm_plex_monitor_throughput - Activate the monitor 10551 10552 Level: developer 10553 10554 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10555 @*/ 10556 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10557 { 10558 PetscLogHandler default_handler; 10559 10560 PetscFunctionBegin; 10561 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10562 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10563 if (default_handler) { 10564 PetscLogEvent event; 10565 PetscEventPerfInfo eventInfo; 10566 PetscReal cellRate, flopRate; 10567 PetscInt cStart, cEnd, Nf, N; 10568 const char *name; 10569 10570 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10571 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10572 PetscCall(DMGetNumFields(dm, &Nf)); 10573 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10574 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10575 N = (cEnd - cStart) * Nf * eventInfo.count; 10576 flopRate = eventInfo.flops / eventInfo.time; 10577 cellRate = N / eventInfo.time; 10578 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))); 10579 } else { 10580 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."); 10581 } 10582 PetscFunctionReturn(PETSC_SUCCESS); 10583 } 10584