1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeMultistage, 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_CreateBoxSFC, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 PetscLogEvent DMPLEX_DistributionView, DMPLEX_DistributionLoad; 17 18 PetscBool Plexcite = PETSC_FALSE; 19 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 20 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 21 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 22 "journal = {SIAM Journal on Scientific Computing},\n" 23 "volume = {38},\n" 24 "number = {5},\n" 25 "pages = {S143--S155},\n" 26 "eprint = {http://arxiv.org/abs/1506.07749},\n" 27 "doi = {10.1137/15M1026092},\n" 28 "year = {2016},\n" 29 "petsc_uses={DMPlex},\n}\n"; 30 31 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 32 33 /*@ 34 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 35 36 Input Parameter: 37 . dm - The `DMPLEX` object 38 39 Output Parameter: 40 . simplex - Flag checking for a simplex 41 42 Level: intermediate 43 44 Note: 45 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 46 If the mesh has no cells, this returns `PETSC_FALSE`. 47 48 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 49 @*/ 50 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 51 { 52 DMPolytopeType ct; 53 PetscInt cStart, cEnd; 54 55 PetscFunctionBegin; 56 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 57 if (cEnd <= cStart) { 58 *simplex = PETSC_FALSE; 59 PetscFunctionReturn(PETSC_SUCCESS); 60 } 61 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 62 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 63 PetscFunctionReturn(PETSC_SUCCESS); 64 } 65 66 /*@ 67 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 68 69 Input Parameters: 70 + dm - The `DMPLEX` object 71 - height - The cell height in the Plex, 0 is the default 72 73 Output Parameters: 74 + cStart - The first "normal" cell, pass `NULL` if not needed 75 - cEnd - The upper bound on "normal" cells, pass `NULL` if not needed 76 77 Level: developer 78 79 Note: 80 This function requires that tensor cells are ordered last. 81 82 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 83 @*/ 84 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PeOp PetscInt *cStart, PeOp PetscInt *cEnd) 85 { 86 DMLabel ctLabel; 87 IS valueIS; 88 const PetscInt *ctypes; 89 PetscBool found = PETSC_FALSE; 90 PetscInt Nct, cS = PETSC_INT_MAX, cE = 0; 91 92 PetscFunctionBegin; 93 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 94 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 95 PetscCall(ISGetLocalSize(valueIS, &Nct)); 96 PetscCall(ISGetIndices(valueIS, &ctypes)); 97 for (PetscInt t = 0; t < Nct; ++t) { 98 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 99 PetscInt ctS, ctE, ht; 100 101 if (ct == DM_POLYTOPE_UNKNOWN) { 102 // If any cells are not typed, just use all cells 103 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 104 break; 105 } 106 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 107 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 108 if (ctS >= ctE) continue; 109 // Check that a point has the right height 110 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 111 if (ht != height) continue; 112 cS = PetscMin(cS, ctS); 113 cE = PetscMax(cE, ctE); 114 found = PETSC_TRUE; 115 } 116 if (!Nct || !found) cS = cE = 0; 117 PetscCall(ISDestroy(&valueIS)); 118 // Reset label for fast lookup 119 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 120 if (cStart) *cStart = cS; 121 if (cEnd) *cEnd = cE; 122 PetscFunctionReturn(PETSC_SUCCESS); 123 } 124 125 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 126 { 127 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 128 PetscInt *sStart, *sEnd; 129 PetscViewerVTKFieldType *ft; 130 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 131 DMLabel depthLabel, ctLabel; 132 133 PetscFunctionBegin; 134 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 135 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 136 PetscCall(DMGetCoordinateDim(dm, &cdim)); 137 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 138 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 139 if (field >= 0) { 140 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 141 } else { 142 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 143 } 144 145 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 146 PetscCall(DMPlexGetDepth(dm, &depth)); 147 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 148 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 149 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 150 const DMPolytopeType ict = (DMPolytopeType)c; 151 PetscInt dep; 152 153 if (ict == DM_POLYTOPE_FV_GHOST) continue; 154 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 155 if (pStart >= 0) { 156 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 157 if (dep != depth - cellHeight) continue; 158 } 159 if (field >= 0) { 160 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 161 } else { 162 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 163 } 164 } 165 166 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 167 *types = 0; 168 169 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 170 if (globalvcdof[c]) ++(*types); 171 } 172 173 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 174 t = 0; 175 if (globalvcdof[DM_NUM_POLYTOPES]) { 176 sStart[t] = vStart; 177 sEnd[t] = vEnd; 178 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 179 ++t; 180 } 181 182 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 183 if (globalvcdof[c]) { 184 const DMPolytopeType ict = (DMPolytopeType)c; 185 186 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 187 sStart[t] = cStart; 188 sEnd[t] = cEnd; 189 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 190 ++t; 191 } 192 } 193 194 if (!*types) { 195 if (field >= 0) { 196 const char *fieldname; 197 198 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 199 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 200 } else { 201 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 202 } 203 } 204 205 *ssStart = sStart; 206 *ssEnd = sEnd; 207 *sft = ft; 208 PetscFunctionReturn(PETSC_SUCCESS); 209 } 210 211 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 212 { 213 PetscFunctionBegin; 214 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 215 PetscFunctionReturn(PETSC_SUCCESS); 216 } 217 218 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 219 { 220 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 221 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 222 223 PetscFunctionBegin; 224 *ft = PETSC_VTK_INVALID; 225 PetscCall(DMGetCoordinateDim(dm, &cdim)); 226 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 227 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 228 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 229 if (field >= 0) { 230 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 231 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 232 } else { 233 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 234 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 235 } 236 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 237 if (globalvcdof[0]) { 238 *sStart = vStart; 239 *sEnd = vEnd; 240 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 241 else *ft = PETSC_VTK_POINT_FIELD; 242 } else if (globalvcdof[1]) { 243 *sStart = cStart; 244 *sEnd = cEnd; 245 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 246 else *ft = PETSC_VTK_CELL_FIELD; 247 } else { 248 if (field >= 0) { 249 const char *fieldname; 250 251 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 252 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 253 } else { 254 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n")); 255 } 256 } 257 PetscFunctionReturn(PETSC_SUCCESS); 258 } 259 260 /*@ 261 DMPlexVecView1D - Plot many 1D solutions on the same line graph 262 263 Collective 264 265 Input Parameters: 266 + dm - The `DMPLEX` object 267 . n - The number of vectors 268 . u - The array of local vectors 269 - viewer - The `PetscViewer` 270 271 Level: advanced 272 273 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 274 @*/ 275 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 276 { 277 DM cdm; 278 PetscDS ds; 279 PetscDraw draw = NULL; 280 PetscDrawLG lg; 281 Vec coordinates; 282 const PetscScalar *coords, **sol; 283 PetscReal *vals; 284 PetscInt *Nc; 285 PetscInt Nf, Nl, vStart, vEnd, eStart, eEnd; 286 char **names; 287 288 PetscFunctionBegin; 289 PetscCall(DMGetCoordinateDM(dm, &cdm)); 290 PetscCall(DMGetDS(dm, &ds)); 291 PetscCall(PetscDSGetNumFields(ds, &Nf)); 292 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 293 PetscCall(PetscDSGetComponents(ds, &Nc)); 294 295 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 296 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 297 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 298 299 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 300 for (PetscInt i = 0, l = 0; i < n; ++i) { 301 const char *vname; 302 303 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 304 for (PetscInt f = 0; f < Nf; ++f) { 305 PetscObject disc; 306 const char *fname; 307 char tmpname[PETSC_MAX_PATH_LEN]; 308 309 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 310 /* TODO Create names for components */ 311 for (PetscInt c = 0; c < Nc[f]; ++c, ++l) { 312 PetscCall(PetscObjectGetName(disc, &fname)); 313 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 314 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 315 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 316 PetscCall(PetscStrallocpy(tmpname, &names[l])); 317 } 318 } 319 } 320 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 321 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 322 PetscCall(VecGetArrayRead(coordinates, &coords)); 323 for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 324 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 325 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 326 PetscSection s; 327 PetscInt cdof, vdof; 328 329 PetscCall(DMGetLocalSection(dm, &s)); 330 PetscCall(PetscSectionGetDof(s, eStart, &cdof)); 331 PetscCall(PetscSectionGetDof(s, vStart, &vdof)); 332 if (cdof) { 333 if (vdof) { 334 // P_2 335 PetscInt vFirst = -1; 336 337 for (PetscInt e = eStart; e < eEnd; ++e) { 338 PetscScalar *xa, *xb, *svals; 339 const PetscInt *cone; 340 341 PetscCall(DMPlexGetCone(dm, e, &cone)); 342 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 343 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 344 if (e == eStart) vFirst = cone[0]; 345 for (PetscInt i = 0; i < n; ++i) { 346 PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals)); 347 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 348 } 349 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals)); 350 if (e == eEnd - 1 && cone[1] != vFirst) { 351 for (PetscInt i = 0; i < n; ++i) { 352 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 353 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 354 } 355 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 356 for (PetscInt i = 0; i < n; ++i) { 357 PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals)); 358 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 359 } 360 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals)); 361 } 362 } 363 } else { 364 // P_0 365 for (PetscInt e = eStart; e < eEnd; ++e) { 366 PetscScalar *xa, *xb, *svals; 367 const PetscInt *cone; 368 369 PetscCall(DMPlexGetCone(dm, e, &cone)); 370 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 371 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 372 for (PetscInt i = 0; i < n; ++i) { 373 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 374 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 375 } 376 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 377 } 378 } 379 } else if (vdof) { 380 // P_1 381 for (PetscInt v = vStart; v < vEnd; ++v) { 382 PetscScalar *x, *svals; 383 384 PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x)); 385 for (PetscInt i = 0; i < n; ++i) { 386 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 387 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 388 } 389 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 390 } 391 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Discretization not supported"); 392 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 393 for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 394 for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 395 PetscCall(PetscFree3(sol, names, vals)); 396 397 PetscCall(PetscDrawLGDraw(lg)); 398 PetscCall(PetscDrawLGDestroy(&lg)); 399 PetscFunctionReturn(PETSC_SUCCESS); 400 } 401 402 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 403 { 404 DM dm; 405 406 PetscFunctionBegin; 407 PetscCall(VecGetDM(u, &dm)); 408 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 409 PetscFunctionReturn(PETSC_SUCCESS); 410 } 411 412 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 413 { 414 DM dm; 415 PetscSection s; 416 PetscDraw draw, popup; 417 DM cdm; 418 PetscSection coordSection; 419 Vec coordinates; 420 const PetscScalar *array; 421 PetscReal lbound[3], ubound[3]; 422 PetscReal vbound[2], time; 423 PetscBool flg; 424 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 425 const char *name; 426 char title[PETSC_MAX_PATH_LEN]; 427 428 PetscFunctionBegin; 429 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 430 PetscCall(VecGetDM(v, &dm)); 431 PetscCall(DMGetCoordinateDim(dm, &dim)); 432 PetscCall(DMGetLocalSection(dm, &s)); 433 PetscCall(PetscSectionGetNumFields(s, &Nf)); 434 PetscCall(DMGetCoarsenLevel(dm, &level)); 435 PetscCall(DMGetCoordinateDM(dm, &cdm)); 436 PetscCall(DMGetLocalSection(cdm, &coordSection)); 437 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 438 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 439 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 440 441 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 442 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 443 444 PetscCall(VecGetLocalSize(coordinates, &N)); 445 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 446 PetscCall(PetscDrawClear(draw)); 447 448 /* Could implement something like DMDASelectFields() */ 449 for (f = 0; f < Nf; ++f) { 450 DM fdm = dm; 451 Vec fv = v; 452 IS fis; 453 char prefix[PETSC_MAX_PATH_LEN]; 454 const char *fname; 455 456 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 457 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 458 459 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 460 else prefix[0] = '\0'; 461 if (Nf > 1) { 462 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 463 PetscCall(VecGetSubVector(v, fis, &fv)); 464 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 465 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 466 } 467 for (comp = 0; comp < Nc; ++comp, ++w) { 468 PetscInt nmax = 2; 469 470 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 471 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 472 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 473 PetscCall(PetscDrawSetTitle(draw, title)); 474 475 /* TODO Get max and min only for this component */ 476 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 477 if (!flg) { 478 PetscCall(VecMin(fv, NULL, &vbound[0])); 479 PetscCall(VecMax(fv, NULL, &vbound[1])); 480 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 481 } 482 483 PetscCall(PetscDrawGetPopup(draw, &popup)); 484 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 485 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 486 PetscCall(VecGetArrayRead(fv, &array)); 487 for (c = cStart; c < cEnd; ++c) { 488 DMPolytopeType ct; 489 PetscScalar *coords = NULL, *a = NULL; 490 const PetscScalar *coords_arr; 491 PetscBool isDG; 492 PetscInt numCoords; 493 int color[4] = {-1, -1, -1, -1}; 494 495 PetscCall(DMPlexGetCellType(dm, c, &ct)); 496 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 497 if (a) { 498 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 499 color[1] = color[2] = color[3] = color[0]; 500 } else { 501 PetscScalar *vals = NULL; 502 PetscInt numVals, va; 503 504 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 505 if (!numVals) { 506 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 507 continue; 508 } 509 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); 510 switch (numVals / Nc) { 511 case 1: /* P1 Clamped Segment Prism */ 512 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 513 PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]); 514 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 515 break; 516 case 3: /* P1 Triangle */ 517 case 4: /* P1 Quadrangle */ 518 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 519 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 520 break; 521 case 6: /* P2 Triangle */ 522 case 8: /* P2 Quadrangle */ 523 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 524 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 525 break; 526 default: 527 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 528 } 529 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 530 } 531 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 532 switch (numCoords) { 533 case 6: 534 case 12: /* Localized triangle */ 535 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])); 536 break; 537 case 8: 538 case 16: /* Localized quadrilateral */ 539 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 540 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 541 } else { 542 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])); 543 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])); 544 } 545 break; 546 default: 547 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 548 } 549 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 550 } 551 PetscCall(VecRestoreArrayRead(fv, &array)); 552 PetscCall(PetscDrawFlush(draw)); 553 PetscCall(PetscDrawPause(draw)); 554 PetscCall(PetscDrawSave(draw)); 555 } 556 if (Nf > 1) { 557 PetscCall(VecRestoreSubVector(v, fis, &fv)); 558 PetscCall(ISDestroy(&fis)); 559 PetscCall(DMDestroy(&fdm)); 560 } 561 } 562 PetscFunctionReturn(PETSC_SUCCESS); 563 } 564 565 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 566 { 567 DM dm; 568 PetscDraw draw; 569 PetscInt dim; 570 PetscBool isnull; 571 572 PetscFunctionBegin; 573 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 574 PetscCall(PetscDrawIsNull(draw, &isnull)); 575 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 576 577 PetscCall(VecGetDM(v, &dm)); 578 PetscCall(DMGetCoordinateDim(dm, &dim)); 579 switch (dim) { 580 case 1: 581 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 582 break; 583 case 2: 584 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 585 break; 586 default: 587 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 588 } 589 PetscFunctionReturn(PETSC_SUCCESS); 590 } 591 592 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 593 { 594 DM dm; 595 Vec locv; 596 const char *name; 597 PetscSection section; 598 PetscInt pStart, pEnd; 599 PetscInt numFields; 600 PetscViewerVTKFieldType ft; 601 602 PetscFunctionBegin; 603 PetscCall(VecGetDM(v, &dm)); 604 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 605 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 606 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 607 PetscCall(VecCopy(v, locv)); 608 PetscCall(DMGetLocalSection(dm, §ion)); 609 PetscCall(PetscSectionGetNumFields(section, &numFields)); 610 if (!numFields) { 611 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 612 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 613 } else { 614 PetscInt f; 615 616 for (f = 0; f < numFields; f++) { 617 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 618 if (ft == PETSC_VTK_INVALID) continue; 619 PetscCall(PetscObjectReference((PetscObject)locv)); 620 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 621 } 622 PetscCall(VecDestroy(&locv)); 623 } 624 PetscFunctionReturn(PETSC_SUCCESS); 625 } 626 627 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 640 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 641 if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) { 642 PetscInt i, numFields; 643 PetscObject fe; 644 PetscBool fem = PETSC_FALSE; 645 Vec locv = v; 646 const char *name; 647 PetscInt step; 648 PetscReal time; 649 650 PetscCall(DMGetNumFields(dm, &numFields)); 651 for (i = 0; i < numFields; i++) { 652 PetscCall(DMGetField(dm, i, NULL, &fe)); 653 if (fe->classid == PETSCFE_CLASSID) { 654 fem = PETSC_TRUE; 655 break; 656 } 657 } 658 if (fem) { 659 PetscObject isZero; 660 661 PetscCall(DMGetLocalVector(dm, &locv)); 662 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 663 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 664 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 665 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 666 PetscCall(VecCopy(v, locv)); 667 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 668 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 669 } 670 if (isvtk) { 671 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 672 } else if (ishdf5) { 673 #if defined(PETSC_HAVE_HDF5) 674 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 675 #else 676 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 677 #endif 678 } else if (isdraw) { 679 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 680 } else if (ispython) { 681 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv)); 682 } else if (isglvis) { 683 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 684 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 685 PetscCall(VecView_GLVis(locv, viewer)); 686 } else if (iscgns) { 687 #if defined(PETSC_HAVE_CGNS) 688 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 689 #else 690 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 691 #endif 692 } 693 if (fem) { 694 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 695 PetscCall(DMRestoreLocalVector(dm, &locv)); 696 } 697 } else { 698 PetscBool isseq; 699 700 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 701 if (isseq) PetscCall(VecView_Seq(v, viewer)); 702 else PetscCall(VecView_MPI(v, viewer)); 703 } 704 PetscFunctionReturn(PETSC_SUCCESS); 705 } 706 707 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 708 { 709 DM dm; 710 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython; 711 712 PetscFunctionBegin; 713 PetscCall(VecGetDM(v, &dm)); 714 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 715 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 716 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 721 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 722 if (isvtk || isdraw || isglvis || iscgns || ispython) { 723 Vec locv; 724 PetscObject isZero; 725 const char *name; 726 727 PetscCall(DMGetLocalVector(dm, &locv)); 728 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 729 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 730 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 731 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 732 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 733 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 734 PetscCall(VecView_Plex_Local(locv, viewer)); 735 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 736 PetscCall(DMRestoreLocalVector(dm, &locv)); 737 } else if (ishdf5) { 738 #if defined(PETSC_HAVE_HDF5) 739 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 740 #else 741 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 742 #endif 743 } else if (isexodusii) { 744 #if defined(PETSC_HAVE_EXODUSII) 745 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 746 #else 747 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 748 #endif 749 } else { 750 PetscBool isseq; 751 752 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 753 if (isseq) PetscCall(VecView_Seq(v, viewer)); 754 else PetscCall(VecView_MPI(v, viewer)); 755 } 756 PetscFunctionReturn(PETSC_SUCCESS); 757 } 758 759 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 760 { 761 DM dm; 762 MPI_Comm comm; 763 PetscViewerFormat format; 764 Vec v; 765 PetscBool isvtk, ishdf5; 766 767 PetscFunctionBegin; 768 PetscCall(VecGetDM(originalv, &dm)); 769 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 770 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 771 PetscCall(PetscViewerGetFormat(viewer, &format)); 772 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 773 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 774 if (format == PETSC_VIEWER_NATIVE) { 775 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 776 /* this need a better fix */ 777 if (dm->useNatural) { 778 const char *vecname; 779 PetscInt n, nroots; 780 781 PetscCheck(dm->sfNatural, comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 782 PetscCall(VecGetLocalSize(originalv, &n)); 783 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 784 PetscCheck(n == nroots, comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 785 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 786 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 787 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 788 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 789 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 790 } else v = originalv; 791 } else v = originalv; 792 793 if (ishdf5) { 794 #if defined(PETSC_HAVE_HDF5) 795 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 796 #else 797 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 798 #endif 799 } else if (isvtk) { 800 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 801 } else { 802 PetscBool isseq; 803 804 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 805 if (isseq) PetscCall(VecView_Seq(v, viewer)); 806 else PetscCall(VecView_MPI(v, viewer)); 807 } 808 if (v != originalv) PetscCall(VecDestroy(&v)); 809 PetscFunctionReturn(PETSC_SUCCESS); 810 } 811 812 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 813 { 814 DM dm; 815 PetscBool ishdf5; 816 817 PetscFunctionBegin; 818 PetscCall(VecGetDM(v, &dm)); 819 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 820 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 821 if (ishdf5) { 822 DM dmBC; 823 Vec gv; 824 const char *name; 825 826 PetscCall(DMGetOutputDM(dm, &dmBC)); 827 PetscCall(DMGetGlobalVector(dmBC, &gv)); 828 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 829 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 830 PetscCall(VecLoad_Default(gv, viewer)); 831 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 832 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 833 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 834 } else PetscCall(VecLoad_Default(v, viewer)); 835 PetscFunctionReturn(PETSC_SUCCESS); 836 } 837 838 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 839 { 840 DM dm; 841 PetscBool ishdf5, isexodusii, iscgns; 842 843 PetscFunctionBegin; 844 PetscCall(VecGetDM(v, &dm)); 845 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 846 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 847 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 848 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 849 if (ishdf5) { 850 #if defined(PETSC_HAVE_HDF5) 851 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 852 #else 853 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 854 #endif 855 } else if (isexodusii) { 856 #if defined(PETSC_HAVE_EXODUSII) 857 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 858 #else 859 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 860 #endif 861 } else if (iscgns) { 862 #if defined(PETSC_HAVE_CGNS) 863 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 864 #else 865 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 866 #endif 867 } else PetscCall(VecLoad_Default(v, viewer)); 868 PetscFunctionReturn(PETSC_SUCCESS); 869 } 870 871 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 872 { 873 DM dm; 874 PetscViewerFormat format; 875 PetscBool ishdf5; 876 877 PetscFunctionBegin; 878 PetscCall(VecGetDM(originalv, &dm)); 879 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 880 PetscCall(PetscViewerGetFormat(viewer, &format)); 881 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 882 if (format == PETSC_VIEWER_NATIVE) { 883 if (dm->useNatural) { 884 if (dm->sfNatural) { 885 if (ishdf5) { 886 #if defined(PETSC_HAVE_HDF5) 887 Vec v; 888 const char *vecname; 889 890 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 891 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 892 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 893 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 894 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 895 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 896 PetscCall(VecDestroy(&v)); 897 #else 898 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 899 #endif 900 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 901 } 902 } else PetscCall(VecLoad_Default(originalv, viewer)); 903 } 904 PetscFunctionReturn(PETSC_SUCCESS); 905 } 906 907 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 908 { 909 PetscSection coordSection; 910 Vec coordinates; 911 DMLabel depthLabel, celltypeLabel; 912 const char *name[4]; 913 const PetscScalar *a; 914 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 915 916 PetscFunctionBegin; 917 PetscCall(DMGetDimension(dm, &dim)); 918 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 919 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 920 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 921 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 922 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 923 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 924 PetscCall(VecGetArrayRead(coordinates, &a)); 925 name[0] = "vertex"; 926 name[1] = "edge"; 927 name[dim - 1] = "face"; 928 name[dim] = "cell"; 929 for (c = cStart; c < cEnd; ++c) { 930 PetscInt *closure = NULL; 931 PetscInt closureSize, cl, ct; 932 933 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 934 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 935 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 936 PetscCall(PetscViewerASCIIPushTab(viewer)); 937 for (cl = 0; cl < closureSize * 2; cl += 2) { 938 PetscInt point = closure[cl], depth, dof, off, d, p; 939 940 if ((point < pStart) || (point >= pEnd)) continue; 941 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 942 if (!dof) continue; 943 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 944 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 945 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 946 for (p = 0; p < dof / dim; ++p) { 947 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 948 for (d = 0; d < dim; ++d) { 949 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 950 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 951 } 952 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 953 } 954 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 955 } 956 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 957 PetscCall(PetscViewerASCIIPopTab(viewer)); 958 } 959 PetscCall(VecRestoreArrayRead(coordinates, &a)); 960 PetscFunctionReturn(PETSC_SUCCESS); 961 } 962 963 typedef enum { 964 CS_CARTESIAN, 965 CS_POLAR, 966 CS_CYLINDRICAL, 967 CS_SPHERICAL 968 } CoordSystem; 969 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 970 971 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 972 { 973 PetscInt i; 974 975 PetscFunctionBegin; 976 if (dim > 3) { 977 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 978 } else { 979 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 980 981 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 982 switch (cs) { 983 case CS_CARTESIAN: 984 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 985 break; 986 case CS_POLAR: 987 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 988 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 989 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 990 break; 991 case CS_CYLINDRICAL: 992 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 993 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 994 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 995 trcoords[2] = coords[2]; 996 break; 997 case CS_SPHERICAL: 998 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 999 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 1000 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 1001 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 1002 break; 1003 } 1004 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 1005 } 1006 PetscFunctionReturn(PETSC_SUCCESS); 1007 } 1008 1009 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 1010 { 1011 DM_Plex *mesh = (DM_Plex *)dm->data; 1012 DM cdm, cdmCell; 1013 PetscSection coordSection, coordSectionCell; 1014 Vec coordinates, coordinatesCell; 1015 PetscViewerFormat format; 1016 1017 PetscFunctionBegin; 1018 PetscCall(PetscViewerGetFormat(viewer, &format)); 1019 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1020 const char *name; 1021 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1022 PetscInt pStart, pEnd, p, numLabels, l; 1023 PetscMPIInt rank, size; 1024 1025 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1026 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1027 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1028 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1029 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1030 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1031 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1032 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1033 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1034 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1035 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1036 PetscCall(DMGetDimension(dm, &dim)); 1037 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1038 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1039 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1040 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1041 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1042 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1043 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1044 for (p = pStart; p < pEnd; ++p) { 1045 PetscInt dof, off, s; 1046 1047 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1048 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1049 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1050 } 1051 PetscCall(PetscViewerFlush(viewer)); 1052 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1053 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1054 for (p = pStart; p < pEnd; ++p) { 1055 PetscInt dof, off, c; 1056 1057 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1058 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1059 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])); 1060 } 1061 PetscCall(PetscViewerFlush(viewer)); 1062 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1063 if (coordSection && coordinates) { 1064 CoordSystem cs = CS_CARTESIAN; 1065 const PetscScalar *array, *arrayCell = NULL; 1066 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1067 PetscMPIInt rank; 1068 const char *name; 1069 1070 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1071 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1072 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1073 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1074 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1075 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1076 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1077 pStart = PetscMin(pvStart, pcStart); 1078 pEnd = PetscMax(pvEnd, pcEnd); 1079 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1080 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1081 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1082 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1083 1084 PetscCall(VecGetArrayRead(coordinates, &array)); 1085 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1086 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1087 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1088 for (p = pStart; p < pEnd; ++p) { 1089 PetscInt dof, off; 1090 1091 if (p >= pvStart && p < pvEnd) { 1092 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1093 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1094 if (dof) { 1095 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1096 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1097 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1098 } 1099 } 1100 if (cdmCell && p >= pcStart && p < pcEnd) { 1101 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1102 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1103 if (dof) { 1104 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1105 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1106 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1107 } 1108 } 1109 } 1110 PetscCall(PetscViewerFlush(viewer)); 1111 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1112 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1113 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1114 } 1115 PetscCall(DMGetNumLabels(dm, &numLabels)); 1116 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1117 for (l = 0; l < numLabels; ++l) { 1118 DMLabel label; 1119 PetscBool isdepth; 1120 const char *name; 1121 1122 PetscCall(DMGetLabelName(dm, l, &name)); 1123 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1124 if (isdepth) continue; 1125 PetscCall(DMGetLabel(dm, name, &label)); 1126 PetscCall(DMLabelView(label, viewer)); 1127 } 1128 if (size > 1) { 1129 PetscSF sf; 1130 1131 PetscCall(DMGetPointSF(dm, &sf)); 1132 PetscCall(PetscSFView(sf, viewer)); 1133 } 1134 if (mesh->periodic.face_sfs) 1135 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1136 PetscCall(PetscViewerFlush(viewer)); 1137 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1138 const char *name, *color; 1139 const char *defcolors[3] = {"gray", "orange", "green"}; 1140 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1141 char lname[PETSC_MAX_PATH_LEN]; 1142 PetscReal scale = 2.0; 1143 PetscReal tikzscale = 1.0; 1144 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1145 double tcoords[3]; 1146 PetscScalar *coords; 1147 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 1148 PetscMPIInt rank, size; 1149 char **names, **colors, **lcolors; 1150 PetscBool flg, lflg; 1151 PetscBT wp = NULL; 1152 PetscInt pEnd, pStart; 1153 1154 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1155 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1156 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1157 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1158 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1159 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1160 PetscCall(DMGetDimension(dm, &dim)); 1161 PetscCall(DMPlexGetDepth(dm, &depth)); 1162 PetscCall(DMGetNumLabels(dm, &numLabels)); 1163 numLabels = PetscMax(numLabels, 10); 1164 numColors = 10; 1165 numLColors = 10; 1166 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1167 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1168 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1169 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1170 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1171 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1172 n = 4; 1173 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1174 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1175 n = 4; 1176 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1177 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1178 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1179 if (!useLabels) numLabels = 0; 1180 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1181 if (!useColors) { 1182 numColors = 3; 1183 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1184 } 1185 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1186 if (!useColors) { 1187 numLColors = 4; 1188 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1189 } 1190 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1191 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1192 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1193 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1194 if (depth < dim) plotEdges = PETSC_FALSE; 1195 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1196 1197 /* filter points with labelvalue != labeldefaultvalue */ 1198 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1199 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1200 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1201 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1202 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1203 if (lflg) { 1204 DMLabel lbl; 1205 1206 PetscCall(DMGetLabel(dm, lname, &lbl)); 1207 if (lbl) { 1208 PetscInt val, defval; 1209 1210 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1211 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1212 for (c = pStart; c < pEnd; c++) { 1213 PetscInt *closure = NULL; 1214 PetscInt closureSize; 1215 1216 PetscCall(DMLabelGetValue(lbl, c, &val)); 1217 if (val == defval) continue; 1218 1219 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1220 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1221 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1222 } 1223 } 1224 } 1225 1226 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1227 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1228 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1229 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1230 \\documentclass[tikz]{standalone}\n\n\ 1231 \\usepackage{pgflibraryshapes}\n\ 1232 \\usetikzlibrary{backgrounds}\n\ 1233 \\usetikzlibrary{arrows}\n\ 1234 \\begin{document}\n")); 1235 if (size > 1) { 1236 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1237 for (p = 0; p < size; ++p) { 1238 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1239 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1240 } 1241 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1242 } 1243 if (drawHasse) { 1244 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1245 1246 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1249 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1258 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1262 } 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1264 1265 /* Plot vertices */ 1266 PetscCall(VecGetArray(coordinates, &coords)); 1267 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1268 for (v = vStart; v < vEnd; ++v) { 1269 PetscInt off, dof, d; 1270 PetscBool isLabeled = PETSC_FALSE; 1271 1272 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1273 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1274 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1275 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1276 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1277 for (d = 0; d < dof; ++d) { 1278 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1279 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1280 } 1281 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1282 if (dim == 3) { 1283 PetscReal tmp = tcoords[1]; 1284 tcoords[1] = tcoords[2]; 1285 tcoords[2] = -tmp; 1286 } 1287 for (d = 0; d < dof; ++d) { 1288 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1289 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1290 } 1291 if (drawHasse) color = colors[0 % numColors]; 1292 else color = colors[rank % numColors]; 1293 for (l = 0; l < numLabels; ++l) { 1294 PetscInt val; 1295 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1296 if (val >= 0) { 1297 color = lcolors[l % numLColors]; 1298 isLabeled = PETSC_TRUE; 1299 break; 1300 } 1301 } 1302 if (drawNumbers[0]) { 1303 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1304 } else if (drawColors[0]) { 1305 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1306 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1307 } 1308 PetscCall(VecRestoreArray(coordinates, &coords)); 1309 PetscCall(PetscViewerFlush(viewer)); 1310 /* Plot edges */ 1311 if (plotEdges) { 1312 PetscCall(VecGetArray(coordinates, &coords)); 1313 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1314 for (e = eStart; e < eEnd; ++e) { 1315 const PetscInt *cone; 1316 PetscInt coneSize, offA, offB, dof, d; 1317 1318 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1319 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1320 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1321 PetscCall(DMPlexGetCone(dm, e, &cone)); 1322 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1323 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1324 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1325 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1326 for (d = 0; d < dof; ++d) { 1327 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1328 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1329 } 1330 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1331 if (dim == 3) { 1332 PetscReal tmp = tcoords[1]; 1333 tcoords[1] = tcoords[2]; 1334 tcoords[2] = -tmp; 1335 } 1336 for (d = 0; d < dof; ++d) { 1337 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1338 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1339 } 1340 if (drawHasse) color = colors[1 % numColors]; 1341 else color = colors[rank % numColors]; 1342 for (l = 0; l < numLabels; ++l) { 1343 PetscInt val; 1344 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1345 if (val >= 0) { 1346 color = lcolors[l % numLColors]; 1347 break; 1348 } 1349 } 1350 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1351 } 1352 PetscCall(VecRestoreArray(coordinates, &coords)); 1353 PetscCall(PetscViewerFlush(viewer)); 1354 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1355 } 1356 /* Plot cells */ 1357 if (dim == 3 || !drawNumbers[1]) { 1358 for (e = eStart; e < eEnd; ++e) { 1359 const PetscInt *cone; 1360 1361 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1362 color = colors[rank % numColors]; 1363 for (l = 0; l < numLabels; ++l) { 1364 PetscInt val; 1365 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1366 if (val >= 0) { 1367 color = lcolors[l % numLColors]; 1368 break; 1369 } 1370 } 1371 PetscCall(DMPlexGetCone(dm, e, &cone)); 1372 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1373 } 1374 } else { 1375 DMPolytopeType ct; 1376 1377 /* Drawing a 2D polygon */ 1378 for (c = cStart; c < cEnd; ++c) { 1379 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1380 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1381 if (DMPolytopeTypeIsHybrid(ct)) { 1382 const PetscInt *cone; 1383 PetscInt coneSize, e; 1384 1385 PetscCall(DMPlexGetCone(dm, c, &cone)); 1386 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1387 for (e = 0; e < coneSize; ++e) { 1388 const PetscInt *econe; 1389 1390 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1391 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)); 1392 } 1393 } else { 1394 PetscInt *closure = NULL; 1395 PetscInt closureSize, Nv = 0, v; 1396 1397 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1398 for (p = 0; p < closureSize * 2; p += 2) { 1399 const PetscInt point = closure[p]; 1400 1401 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1402 } 1403 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1404 for (v = 0; v <= Nv; ++v) { 1405 const PetscInt vertex = closure[v % Nv]; 1406 1407 if (v > 0) { 1408 if (plotEdges) { 1409 const PetscInt *edge; 1410 PetscInt endpoints[2], ne; 1411 1412 endpoints[0] = closure[v - 1]; 1413 endpoints[1] = vertex; 1414 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1415 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1416 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1417 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1418 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1419 } 1420 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1421 } 1422 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1423 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1424 } 1425 } 1426 } 1427 for (c = cStart; c < cEnd; ++c) { 1428 double ccoords[3] = {0.0, 0.0, 0.0}; 1429 PetscBool isLabeled = PETSC_FALSE; 1430 PetscScalar *cellCoords = NULL; 1431 const PetscScalar *array; 1432 PetscInt numCoords, cdim, d; 1433 PetscBool isDG; 1434 1435 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1436 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1437 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1438 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1439 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1440 for (p = 0; p < numCoords / cdim; ++p) { 1441 for (d = 0; d < cdim; ++d) { 1442 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1443 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1444 } 1445 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1446 if (cdim == 3) { 1447 PetscReal tmp = tcoords[1]; 1448 tcoords[1] = tcoords[2]; 1449 tcoords[2] = -tmp; 1450 } 1451 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1452 } 1453 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1454 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1455 for (d = 0; d < cdim; ++d) { 1456 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1457 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1458 } 1459 if (drawHasse) color = colors[depth % numColors]; 1460 else color = colors[rank % numColors]; 1461 for (l = 0; l < numLabels; ++l) { 1462 PetscInt val; 1463 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1464 if (val >= 0) { 1465 color = lcolors[l % numLColors]; 1466 isLabeled = PETSC_TRUE; 1467 break; 1468 } 1469 } 1470 if (drawNumbers[dim]) { 1471 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1472 } else if (drawColors[dim]) { 1473 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1474 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1475 } 1476 if (drawHasse) { 1477 int height = 0; 1478 1479 color = colors[depth % numColors]; 1480 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1481 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1482 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1483 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1484 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1485 1486 if (depth > 2) { 1487 color = colors[1 % numColors]; 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1489 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1490 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1491 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1492 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1493 } 1494 1495 color = colors[1 % numColors]; 1496 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1497 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1498 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1499 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1500 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1501 1502 color = colors[0 % numColors]; 1503 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1504 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1505 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1506 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1507 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1508 1509 for (p = pStart; p < pEnd; ++p) { 1510 const PetscInt *cone; 1511 PetscInt coneSize, cp; 1512 1513 PetscCall(DMPlexGetCone(dm, p, &cone)); 1514 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1515 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1516 } 1517 } 1518 PetscCall(PetscViewerFlush(viewer)); 1519 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1520 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1521 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1522 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1523 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1524 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1525 PetscCall(PetscFree3(names, colors, lcolors)); 1526 PetscCall(PetscBTDestroy(&wp)); 1527 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1528 Vec cown, acown; 1529 VecScatter sct; 1530 ISLocalToGlobalMapping g2l; 1531 IS gid, acis; 1532 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1533 MPI_Group ggroup, ngroup; 1534 PetscScalar *array, nid; 1535 const PetscInt *idxs; 1536 PetscInt *idxs2, *start, *adjacency, *work; 1537 PetscInt64 lm[3], gm[3]; 1538 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1539 PetscMPIInt d1, d2, rank; 1540 1541 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1542 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1543 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1544 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1545 #endif 1546 if (ncomm != MPI_COMM_NULL) { 1547 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1548 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1549 d1 = 0; 1550 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1551 nid = d2; 1552 PetscCallMPI(MPI_Group_free(&ggroup)); 1553 PetscCallMPI(MPI_Group_free(&ngroup)); 1554 PetscCallMPI(MPI_Comm_free(&ncomm)); 1555 } else nid = 0.0; 1556 1557 /* Get connectivity */ 1558 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1559 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1560 1561 /* filter overlapped local cells */ 1562 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1563 PetscCall(ISGetIndices(gid, &idxs)); 1564 PetscCall(ISGetLocalSize(gid, &cum)); 1565 PetscCall(PetscMalloc1(cum, &idxs2)); 1566 for (c = cStart, cum = 0; c < cEnd; c++) { 1567 if (idxs[c - cStart] < 0) continue; 1568 idxs2[cum++] = idxs[c - cStart]; 1569 } 1570 PetscCall(ISRestoreIndices(gid, &idxs)); 1571 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1572 PetscCall(ISDestroy(&gid)); 1573 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1574 1575 /* support for node-aware cell locality */ 1576 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1577 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1578 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1579 PetscCall(VecGetArray(cown, &array)); 1580 for (c = 0; c < numVertices; c++) array[c] = nid; 1581 PetscCall(VecRestoreArray(cown, &array)); 1582 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1583 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1584 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1585 PetscCall(ISDestroy(&acis)); 1586 PetscCall(VecScatterDestroy(&sct)); 1587 PetscCall(VecDestroy(&cown)); 1588 1589 /* compute edgeCut */ 1590 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1591 PetscCall(PetscMalloc1(cum, &work)); 1592 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1593 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1594 PetscCall(ISDestroy(&gid)); 1595 PetscCall(VecGetArray(acown, &array)); 1596 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1597 PetscInt totl; 1598 1599 totl = start[c + 1] - start[c]; 1600 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1601 for (i = 0; i < totl; i++) { 1602 if (work[i] < 0) { 1603 ect += 1; 1604 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1605 } 1606 } 1607 } 1608 PetscCall(PetscFree(work)); 1609 PetscCall(VecRestoreArray(acown, &array)); 1610 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1611 lm[1] = -numVertices; 1612 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1613 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1614 lm[0] = ect; /* edgeCut */ 1615 lm[1] = ectn; /* node-aware edgeCut */ 1616 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1617 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1618 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1619 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1620 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1621 #else 1622 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1623 #endif 1624 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1625 PetscCall(PetscFree(start)); 1626 PetscCall(PetscFree(adjacency)); 1627 PetscCall(VecDestroy(&acown)); 1628 } else { 1629 const char *name; 1630 PetscInt *sizes, *hybsizes, *ghostsizes; 1631 PetscInt locDepth, depth, cellHeight, dim, d; 1632 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1633 PetscInt numLabels, l, maxSize = 17; 1634 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1635 MPI_Comm comm; 1636 PetscMPIInt size, rank; 1637 1638 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1639 PetscCallMPI(MPI_Comm_size(comm, &size)); 1640 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1641 PetscCall(DMGetDimension(dm, &dim)); 1642 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1643 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1644 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1645 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1646 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1647 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1648 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1649 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1650 gcNum = gcEnd - gcStart; 1651 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1652 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1653 for (d = 0; d <= depth; d++) { 1654 PetscInt Nc[2] = {0, 0}, ict; 1655 1656 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1657 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1658 ict = ct0; 1659 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1660 ct0 = (DMPolytopeType)ict; 1661 for (p = pStart; p < pEnd; ++p) { 1662 DMPolytopeType ct; 1663 1664 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1665 if (ct == ct0) ++Nc[0]; 1666 else ++Nc[1]; 1667 } 1668 if (size < maxSize) { 1669 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1670 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1671 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1672 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1673 for (p = 0; p < size; ++p) { 1674 if (rank == 0) { 1675 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1676 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1677 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1678 } 1679 } 1680 } else { 1681 PetscInt locMinMax[2]; 1682 1683 locMinMax[0] = Nc[0] + Nc[1]; 1684 locMinMax[1] = Nc[0] + Nc[1]; 1685 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1686 locMinMax[0] = Nc[1]; 1687 locMinMax[1] = Nc[1]; 1688 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1689 if (d == depth) { 1690 locMinMax[0] = gcNum; 1691 locMinMax[1] = gcNum; 1692 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1693 } 1694 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1695 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1696 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1697 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1698 } 1699 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1700 } 1701 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1702 { 1703 const PetscReal *maxCell; 1704 const PetscReal *L; 1705 PetscBool localized; 1706 1707 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1708 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1709 if (L || localized) { 1710 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1711 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1712 if (L) { 1713 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1714 for (d = 0; d < dim; ++d) { 1715 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1716 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1717 } 1718 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1719 } 1720 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1721 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1722 } 1723 } 1724 PetscCall(DMGetNumLabels(dm, &numLabels)); 1725 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1726 for (l = 0; l < numLabels; ++l) { 1727 DMLabel label; 1728 const char *name; 1729 PetscInt *values; 1730 PetscInt numValues, v; 1731 1732 PetscCall(DMGetLabelName(dm, l, &name)); 1733 PetscCall(DMGetLabel(dm, name, &label)); 1734 PetscCall(DMLabelGetNumValues(label, &numValues)); 1735 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1736 1737 { // Extract array of DMLabel values so it can be sorted 1738 IS is_values; 1739 const PetscInt *is_values_local = NULL; 1740 1741 PetscCall(DMLabelGetValueIS(label, &is_values)); 1742 PetscCall(ISGetIndices(is_values, &is_values_local)); 1743 PetscCall(PetscMalloc1(numValues, &values)); 1744 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1745 PetscCall(PetscSortInt(numValues, values)); 1746 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1747 PetscCall(ISDestroy(&is_values)); 1748 } 1749 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1750 for (v = 0; v < numValues; ++v) { 1751 PetscInt size; 1752 1753 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1754 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1755 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1756 } 1757 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1758 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1759 PetscCall(PetscFree(values)); 1760 } 1761 { 1762 char **labelNames; 1763 PetscInt Nl = numLabels; 1764 PetscBool flg; 1765 1766 PetscCall(PetscMalloc1(Nl, &labelNames)); 1767 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1768 for (l = 0; l < Nl; ++l) { 1769 DMLabel label; 1770 1771 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1772 if (flg) { 1773 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1774 PetscCall(DMLabelView(label, viewer)); 1775 } 1776 PetscCall(PetscFree(labelNames[l])); 1777 } 1778 PetscCall(PetscFree(labelNames)); 1779 } 1780 /* If no fields are specified, people do not want to see adjacency */ 1781 if (dm->Nf) { 1782 PetscInt f; 1783 1784 for (f = 0; f < dm->Nf; ++f) { 1785 const char *name; 1786 1787 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1788 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1789 PetscCall(PetscViewerASCIIPushTab(viewer)); 1790 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1791 if (dm->fields[f].adjacency[0]) { 1792 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1793 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1794 } else { 1795 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1796 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1797 } 1798 PetscCall(PetscViewerASCIIPopTab(viewer)); 1799 } 1800 } 1801 DMPlexTransform tr; 1802 1803 PetscCall(DMPlexGetTransform(dm, &tr)); 1804 if (tr) { 1805 PetscCall(PetscViewerASCIIPushTab(viewer)); 1806 PetscCall(PetscViewerASCIIPrintf(viewer, "Created using transform:\n")); 1807 PetscCall(DMPlexTransformView(tr, viewer)); 1808 PetscCall(PetscViewerASCIIPopTab(viewer)); 1809 } 1810 PetscCall(DMGetCoarseDM(dm, &cdm)); 1811 if (cdm) { 1812 PetscCall(PetscViewerASCIIPushTab(viewer)); 1813 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1814 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1815 PetscCall(PetscViewerASCIIPopTab(viewer)); 1816 } 1817 } 1818 PetscFunctionReturn(PETSC_SUCCESS); 1819 } 1820 1821 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt lC, PetscInt cC, PetscInt cell, const PetscScalar coords[]) 1822 { 1823 DMPolytopeType ct; 1824 PetscMPIInt rank; 1825 PetscInt cdim; 1826 int lineColor, cellColor; 1827 1828 PetscFunctionBegin; 1829 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1830 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1831 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1832 lineColor = (int)(lC < 0 ? PETSC_DRAW_BLACK : lC); 1833 cellColor = (int)(cC < 0 ? PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2 : cC); 1834 switch (ct) { 1835 case DM_POLYTOPE_SEGMENT: 1836 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1837 switch (cdim) { 1838 case 1: { 1839 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1840 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1841 1842 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, lineColor)); 1843 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, lineColor)); 1844 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, lineColor)); 1845 } break; 1846 case 2: { 1847 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1848 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1849 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1850 1851 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1852 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, lineColor)); 1853 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, lineColor)); 1854 } break; 1855 default: 1856 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1857 } 1858 break; 1859 case DM_POLYTOPE_TRIANGLE: 1860 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1861 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1862 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1863 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1864 break; 1865 case DM_POLYTOPE_QUADRILATERAL: 1866 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1867 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), cellColor, cellColor, cellColor)); 1868 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1869 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1870 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor)); 1871 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1872 break; 1873 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1874 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1875 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1876 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1877 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor)); 1878 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1879 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1880 break; 1881 case DM_POLYTOPE_FV_GHOST: 1882 break; 1883 default: 1884 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1885 } 1886 PetscFunctionReturn(PETSC_SUCCESS); 1887 } 1888 1889 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1890 { 1891 PetscReal centroid[2] = {0., 0.}; 1892 PetscMPIInt rank; 1893 PetscMPIInt fillColor; 1894 1895 PetscFunctionBegin; 1896 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1897 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1898 for (PetscInt v = 0; v < Nv; ++v) { 1899 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1900 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1901 } 1902 for (PetscInt e = 0; e < Nv; ++e) { 1903 refCoords[0] = refVertices[e * 2 + 0]; 1904 refCoords[1] = refVertices[e * 2 + 1]; 1905 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1906 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1907 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1908 } 1909 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1910 for (PetscInt d = 0; d < edgeDiv; ++d) { 1911 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)); 1912 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1913 } 1914 } 1915 PetscFunctionReturn(PETSC_SUCCESS); 1916 } 1917 1918 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1919 { 1920 DMPolytopeType ct; 1921 1922 PetscFunctionBegin; 1923 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1924 switch (ct) { 1925 case DM_POLYTOPE_TRIANGLE: { 1926 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1927 1928 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1929 } break; 1930 case DM_POLYTOPE_QUADRILATERAL: { 1931 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1932 1933 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1934 } break; 1935 default: 1936 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1937 } 1938 PetscFunctionReturn(PETSC_SUCCESS); 1939 } 1940 1941 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1942 { 1943 PetscDraw draw; 1944 DM cdm; 1945 PetscSection coordSection; 1946 Vec coordinates; 1947 PetscReal xyl[3], xyr[3]; 1948 PetscReal *refCoords, *edgeCoords; 1949 PetscBool isnull, drawAffine; 1950 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv, lineColor = PETSC_DETERMINE, cellColor = PETSC_DETERMINE; 1951 1952 PetscFunctionBegin; 1953 PetscCall(DMGetCoordinateDim(dm, &dim)); 1954 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1955 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1956 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1957 edgeDiv = cDegree + 1; 1958 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_line_color", &lineColor, NULL)); 1959 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_cell_color", &cellColor, NULL)); 1960 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1961 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1962 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1963 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1964 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1965 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1966 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1967 1968 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1969 PetscCall(PetscDrawIsNull(draw, &isnull)); 1970 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1971 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1972 1973 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1974 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1975 PetscCall(PetscDrawClear(draw)); 1976 1977 for (c = cStart; c < cEnd; ++c) { 1978 PetscScalar *coords = NULL; 1979 const PetscScalar *coords_arr; 1980 PetscInt numCoords; 1981 PetscBool isDG; 1982 1983 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1984 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, lineColor, cellColor, c, coords)); 1985 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1986 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1987 } 1988 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1989 PetscCall(PetscDrawFlush(draw)); 1990 PetscCall(PetscDrawPause(draw)); 1991 PetscCall(PetscDrawSave(draw)); 1992 PetscFunctionReturn(PETSC_SUCCESS); 1993 } 1994 1995 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1996 { 1997 DM odm = dm, rdm = dm, cdm; 1998 PetscFE fe; 1999 PetscSpace sp; 2000 PetscClassId id; 2001 PetscInt degree; 2002 PetscBool hoView = PETSC_TRUE; 2003 2004 PetscFunctionBegin; 2005 PetscObjectOptionsBegin((PetscObject)dm); 2006 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 2007 PetscOptionsEnd(); 2008 PetscCall(PetscObjectReference((PetscObject)dm)); 2009 *hdm = dm; 2010 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 2011 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2012 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 2013 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 2014 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 2015 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 2016 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 2017 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 2018 DM cdm, rcdm; 2019 Mat In; 2020 Vec cl, rcl; 2021 2022 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 2023 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, PETSC_FALSE)); 2024 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 2025 PetscCall(DMGetCoordinateDM(odm, &cdm)); 2026 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 2027 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 2028 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 2029 PetscCall(DMSetCoarseDM(rcdm, cdm)); 2030 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 2031 PetscCall(MatMult(In, cl, rcl)); 2032 PetscCall(MatDestroy(&In)); 2033 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 2034 PetscCall(DMDestroy(&odm)); 2035 odm = rdm; 2036 } 2037 *hdm = rdm; 2038 PetscFunctionReturn(PETSC_SUCCESS); 2039 } 2040 2041 #if defined(PETSC_HAVE_EXODUSII) 2042 #include <exodusII.h> 2043 #include <petscviewerexodusii.h> 2044 #endif 2045 2046 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 2047 { 2048 PetscBool isascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 2049 char name[PETSC_MAX_PATH_LEN]; 2050 2051 PetscFunctionBegin; 2052 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2053 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2054 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 2055 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2056 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2057 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2058 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 2059 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 2060 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 2061 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2062 if (isascii) { 2063 PetscViewerFormat format; 2064 PetscCall(PetscViewerGetFormat(viewer, &format)); 2065 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 2066 else PetscCall(DMPlexView_Ascii(dm, viewer)); 2067 } else if (ishdf5) { 2068 #if defined(PETSC_HAVE_HDF5) 2069 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 2070 #else 2071 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2072 #endif 2073 } else if (isvtk) { 2074 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2075 } else if (isdraw) { 2076 DM hdm; 2077 2078 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2079 PetscCall(DMPlexView_Draw(hdm, viewer)); 2080 PetscCall(DMDestroy(&hdm)); 2081 } else if (isglvis) { 2082 PetscCall(DMPlexView_GLVis(dm, viewer)); 2083 #if defined(PETSC_HAVE_EXODUSII) 2084 } else if (isexodus) { 2085 /* 2086 ExodusII requires that all sets be part of exactly one cell set. 2087 If the dm does not have a "Cell Sets" label defined, we create one 2088 with ID 1, containing all cells. 2089 Note that if the Cell Sets label is defined but does not cover all cells, 2090 we may still have a problem. This should probably be checked here or in the viewer; 2091 */ 2092 PetscInt numCS; 2093 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2094 if (!numCS) { 2095 PetscInt cStart, cEnd, c; 2096 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2097 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2098 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2099 } 2100 PetscCall(DMView_PlexExodusII(dm, viewer)); 2101 #endif 2102 #if defined(PETSC_HAVE_CGNS) 2103 } else if (iscgns) { 2104 PetscCall(DMView_PlexCGNS(dm, viewer)); 2105 #endif 2106 } else if (ispython) { 2107 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2108 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2109 /* Optionally view the partition */ 2110 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2111 if (flg) { 2112 Vec ranks; 2113 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2114 PetscCall(VecView(ranks, viewer)); 2115 PetscCall(VecDestroy(&ranks)); 2116 } 2117 /* Optionally view a label */ 2118 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2119 if (flg) { 2120 DMLabel label; 2121 Vec val; 2122 2123 PetscCall(DMGetLabel(dm, name, &label)); 2124 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2125 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2126 PetscCall(VecView(val, viewer)); 2127 PetscCall(VecDestroy(&val)); 2128 } 2129 PetscFunctionReturn(PETSC_SUCCESS); 2130 } 2131 2132 /*@ 2133 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2134 2135 Collective 2136 2137 Input Parameters: 2138 + dm - The `DM` whose topology is to be saved 2139 - viewer - The `PetscViewer` to save it in 2140 2141 Level: advanced 2142 2143 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2144 @*/ 2145 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2146 { 2147 PetscBool ishdf5; 2148 2149 PetscFunctionBegin; 2150 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2151 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2152 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2153 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2154 if (ishdf5) { 2155 #if defined(PETSC_HAVE_HDF5) 2156 IS globalPointNumbering; 2157 PetscViewerFormat format; 2158 2159 PetscCall(PetscViewerGetFormat(viewer, &format)); 2160 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2161 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2162 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2163 PetscCall(ISDestroy(&globalPointNumbering)); 2164 #else 2165 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2166 #endif 2167 } 2168 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2169 PetscFunctionReturn(PETSC_SUCCESS); 2170 } 2171 2172 /*@ 2173 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2174 2175 Collective 2176 2177 Input Parameters: 2178 + dm - The `DM` whose coordinates are to be saved 2179 - viewer - The `PetscViewer` for saving 2180 2181 Level: advanced 2182 2183 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2184 @*/ 2185 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2186 { 2187 PetscBool ishdf5; 2188 2189 PetscFunctionBegin; 2190 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2191 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2192 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2193 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2194 if (ishdf5) { 2195 #if defined(PETSC_HAVE_HDF5) 2196 PetscViewerFormat format; 2197 2198 PetscCall(PetscViewerGetFormat(viewer, &format)); 2199 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2200 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2201 #else 2202 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2203 #endif 2204 } 2205 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2206 PetscFunctionReturn(PETSC_SUCCESS); 2207 } 2208 2209 /*@ 2210 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2211 2212 Collective 2213 2214 Input Parameters: 2215 + dm - The `DM` whose labels are to be saved 2216 - viewer - The `PetscViewer` for saving 2217 2218 Level: advanced 2219 2220 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2221 @*/ 2222 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2223 { 2224 PetscBool ishdf5; 2225 2226 PetscFunctionBegin; 2227 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2228 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2229 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2230 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2231 if (ishdf5) { 2232 #if defined(PETSC_HAVE_HDF5) 2233 IS globalPointNumbering; 2234 PetscViewerFormat format; 2235 2236 PetscCall(PetscViewerGetFormat(viewer, &format)); 2237 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2238 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2239 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2240 PetscCall(ISDestroy(&globalPointNumbering)); 2241 #else 2242 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2243 #endif 2244 } 2245 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2246 PetscFunctionReturn(PETSC_SUCCESS); 2247 } 2248 2249 /*@ 2250 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2251 2252 Collective 2253 2254 Input Parameters: 2255 + dm - The `DM` that contains the topology on which the section to be saved is defined 2256 . viewer - The `PetscViewer` for saving 2257 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2258 2259 Level: advanced 2260 2261 Notes: 2262 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. 2263 2264 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. 2265 2266 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2267 @*/ 2268 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2269 { 2270 PetscBool ishdf5; 2271 2272 PetscFunctionBegin; 2273 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2274 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2275 if (!sectiondm) sectiondm = dm; 2276 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2277 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2278 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2279 if (ishdf5) { 2280 #if defined(PETSC_HAVE_HDF5) 2281 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2282 #else 2283 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2284 #endif 2285 } 2286 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2287 PetscFunctionReturn(PETSC_SUCCESS); 2288 } 2289 2290 /*@ 2291 DMPlexGlobalVectorView - Saves a global vector 2292 2293 Collective 2294 2295 Input Parameters: 2296 + dm - The `DM` that represents the topology 2297 . viewer - The `PetscViewer` to save data with 2298 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2299 - vec - The global vector to be saved 2300 2301 Level: advanced 2302 2303 Notes: 2304 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. 2305 2306 Calling sequence: 2307 .vb 2308 DMCreate(PETSC_COMM_WORLD, &dm); 2309 DMSetType(dm, DMPLEX); 2310 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2311 DMClone(dm, §iondm); 2312 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2313 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2314 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2315 PetscSectionSetChart(section, pStart, pEnd); 2316 PetscSectionSetUp(section); 2317 DMSetLocalSection(sectiondm, section); 2318 PetscSectionDestroy(§ion); 2319 DMGetGlobalVector(sectiondm, &vec); 2320 PetscObjectSetName((PetscObject)vec, "vec_name"); 2321 DMPlexTopologyView(dm, viewer); 2322 DMPlexSectionView(dm, viewer, sectiondm); 2323 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2324 DMRestoreGlobalVector(sectiondm, &vec); 2325 DMDestroy(§iondm); 2326 DMDestroy(&dm); 2327 .ve 2328 2329 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2330 @*/ 2331 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2332 { 2333 PetscBool ishdf5; 2334 2335 PetscFunctionBegin; 2336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2337 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2338 if (!sectiondm) sectiondm = dm; 2339 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2340 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2341 /* Check consistency */ 2342 { 2343 PetscSection section; 2344 PetscBool includesConstraints; 2345 PetscInt m, m1; 2346 2347 PetscCall(VecGetLocalSize(vec, &m1)); 2348 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2349 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2350 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2351 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2352 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2353 } 2354 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2355 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2356 if (ishdf5) { 2357 #if defined(PETSC_HAVE_HDF5) 2358 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2359 #else 2360 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2361 #endif 2362 } 2363 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2364 PetscFunctionReturn(PETSC_SUCCESS); 2365 } 2366 2367 /*@ 2368 DMPlexLocalVectorView - Saves a local vector 2369 2370 Collective 2371 2372 Input Parameters: 2373 + dm - The `DM` that represents the topology 2374 . viewer - The `PetscViewer` to save data with 2375 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2376 - vec - The local vector to be saved 2377 2378 Level: advanced 2379 2380 Note: 2381 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. 2382 2383 Calling sequence: 2384 .vb 2385 DMCreate(PETSC_COMM_WORLD, &dm); 2386 DMSetType(dm, DMPLEX); 2387 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2388 DMClone(dm, §iondm); 2389 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2390 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2391 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2392 PetscSectionSetChart(section, pStart, pEnd); 2393 PetscSectionSetUp(section); 2394 DMSetLocalSection(sectiondm, section); 2395 DMGetLocalVector(sectiondm, &vec); 2396 PetscObjectSetName((PetscObject)vec, "vec_name"); 2397 DMPlexTopologyView(dm, viewer); 2398 DMPlexSectionView(dm, viewer, sectiondm); 2399 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2400 DMRestoreLocalVector(sectiondm, &vec); 2401 DMDestroy(§iondm); 2402 DMDestroy(&dm); 2403 .ve 2404 2405 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2406 @*/ 2407 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2408 { 2409 PetscBool ishdf5; 2410 2411 PetscFunctionBegin; 2412 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2413 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2414 if (!sectiondm) sectiondm = dm; 2415 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2416 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2417 /* Check consistency */ 2418 { 2419 PetscSection section; 2420 PetscBool includesConstraints; 2421 PetscInt m, m1; 2422 2423 PetscCall(VecGetLocalSize(vec, &m1)); 2424 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2425 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2426 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2427 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2428 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2429 } 2430 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2431 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2432 if (ishdf5) { 2433 #if defined(PETSC_HAVE_HDF5) 2434 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2435 #else 2436 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2437 #endif 2438 } 2439 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2440 PetscFunctionReturn(PETSC_SUCCESS); 2441 } 2442 2443 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2444 { 2445 PetscBool ishdf5; 2446 2447 PetscFunctionBegin; 2448 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2449 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2450 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2451 if (ishdf5) { 2452 #if defined(PETSC_HAVE_HDF5) 2453 PetscViewerFormat format; 2454 PetscCall(PetscViewerGetFormat(viewer, &format)); 2455 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2456 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2457 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2458 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2459 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2460 PetscFunctionReturn(PETSC_SUCCESS); 2461 #else 2462 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2463 #endif 2464 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2465 } 2466 2467 /*@ 2468 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2469 2470 Collective 2471 2472 Input Parameters: 2473 + dm - The `DM` into which the topology is loaded 2474 - viewer - The `PetscViewer` for the saved topology 2475 2476 Output Parameter: 2477 . 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; 2478 `NULL` if unneeded 2479 2480 Level: advanced 2481 2482 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2483 `PetscViewer`, `PetscSF` 2484 @*/ 2485 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2486 { 2487 PetscBool ishdf5; 2488 2489 PetscFunctionBegin; 2490 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2491 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2492 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2493 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2494 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2495 if (ishdf5) { 2496 #if defined(PETSC_HAVE_HDF5) 2497 PetscViewerFormat format; 2498 2499 PetscCall(PetscViewerGetFormat(viewer, &format)); 2500 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2501 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2502 #else 2503 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2504 #endif 2505 } 2506 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2507 PetscFunctionReturn(PETSC_SUCCESS); 2508 } 2509 2510 /*@ 2511 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2512 2513 Collective 2514 2515 Input Parameters: 2516 + dm - The `DM` into which the coordinates are loaded 2517 . viewer - The `PetscViewer` for the saved coordinates 2518 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2519 2520 Level: advanced 2521 2522 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2523 `PetscSF`, `PetscViewer` 2524 @*/ 2525 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2526 { 2527 PetscBool ishdf5; 2528 2529 PetscFunctionBegin; 2530 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2531 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2532 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2533 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2534 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2535 if (ishdf5) { 2536 #if defined(PETSC_HAVE_HDF5) 2537 PetscViewerFormat format; 2538 2539 PetscCall(PetscViewerGetFormat(viewer, &format)); 2540 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2541 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2542 #else 2543 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2544 #endif 2545 } 2546 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2547 PetscFunctionReturn(PETSC_SUCCESS); 2548 } 2549 2550 /*@ 2551 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2552 2553 Collective 2554 2555 Input Parameters: 2556 + dm - The `DM` into which the labels are loaded 2557 . viewer - The `PetscViewer` for the saved labels 2558 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2559 2560 Level: advanced 2561 2562 Note: 2563 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2564 2565 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2566 `PetscSF`, `PetscViewer` 2567 @*/ 2568 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2569 { 2570 PetscBool ishdf5; 2571 2572 PetscFunctionBegin; 2573 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2574 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2575 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2576 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2577 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2578 if (ishdf5) { 2579 #if defined(PETSC_HAVE_HDF5) 2580 PetscViewerFormat format; 2581 2582 PetscCall(PetscViewerGetFormat(viewer, &format)); 2583 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2584 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2585 #else 2586 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2587 #endif 2588 } 2589 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2590 PetscFunctionReturn(PETSC_SUCCESS); 2591 } 2592 2593 /*@ 2594 DMPlexSectionLoad - Loads section into a `DMPLEX` 2595 2596 Collective 2597 2598 Input Parameters: 2599 + dm - The `DM` that represents the topology 2600 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2601 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2602 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2603 2604 Output Parameters: 2605 + 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) 2606 - 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) 2607 2608 Level: advanced 2609 2610 Notes: 2611 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. 2612 2613 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. 2614 2615 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. 2616 2617 Example using 2 processes: 2618 .vb 2619 NX (number of points on dm): 4 2620 sectionA : the on-disk section 2621 vecA : a vector associated with sectionA 2622 sectionB : sectiondm's local section constructed in this function 2623 vecB (local) : a vector associated with sectiondm's local section 2624 vecB (global) : a vector associated with sectiondm's global section 2625 2626 rank 0 rank 1 2627 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2628 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2629 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2630 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2631 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2632 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2633 sectionB->atlasDof : 1 0 1 | 1 3 2634 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2635 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2636 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2637 .ve 2638 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2639 2640 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2641 @*/ 2642 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, PeOp DM sectiondm, PetscSF globalToLocalPointSF, PeOp PetscSF *globalDofSF, PeOp PetscSF *localDofSF) 2643 { 2644 PetscBool ishdf5; 2645 2646 PetscFunctionBegin; 2647 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2648 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2649 if (!sectiondm) sectiondm = dm; 2650 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2651 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2652 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2653 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2654 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2655 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2656 if (ishdf5) { 2657 #if defined(PETSC_HAVE_HDF5) 2658 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2659 #else 2660 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2661 #endif 2662 } 2663 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2664 PetscFunctionReturn(PETSC_SUCCESS); 2665 } 2666 2667 /*@ 2668 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2669 2670 Collective 2671 2672 Input Parameters: 2673 + dm - The `DM` that represents the topology 2674 . viewer - The `PetscViewer` that represents the on-disk vector data 2675 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2676 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2677 - vec - The global vector to set values of 2678 2679 Level: advanced 2680 2681 Notes: 2682 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. 2683 2684 Calling sequence: 2685 .vb 2686 DMCreate(PETSC_COMM_WORLD, &dm); 2687 DMSetType(dm, DMPLEX); 2688 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2689 DMPlexTopologyLoad(dm, viewer, &sfX); 2690 DMClone(dm, §iondm); 2691 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2692 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2693 DMGetGlobalVector(sectiondm, &vec); 2694 PetscObjectSetName((PetscObject)vec, "vec_name"); 2695 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2696 DMRestoreGlobalVector(sectiondm, &vec); 2697 PetscSFDestroy(&gsf); 2698 PetscSFDestroy(&sfX); 2699 DMDestroy(§iondm); 2700 DMDestroy(&dm); 2701 .ve 2702 2703 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2704 `PetscSF`, `PetscViewer` 2705 @*/ 2706 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2707 { 2708 PetscBool ishdf5; 2709 2710 PetscFunctionBegin; 2711 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2712 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2713 if (!sectiondm) sectiondm = dm; 2714 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2715 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2716 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2717 /* Check consistency */ 2718 { 2719 PetscSection section; 2720 PetscBool includesConstraints; 2721 PetscInt m, m1; 2722 2723 PetscCall(VecGetLocalSize(vec, &m1)); 2724 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2725 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2726 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2727 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2728 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2729 } 2730 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2731 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2732 if (ishdf5) { 2733 #if defined(PETSC_HAVE_HDF5) 2734 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2735 #else 2736 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2737 #endif 2738 } 2739 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2740 PetscFunctionReturn(PETSC_SUCCESS); 2741 } 2742 2743 /*@ 2744 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2745 2746 Collective 2747 2748 Input Parameters: 2749 + dm - The `DM` that represents the topology 2750 . viewer - The `PetscViewer` that represents the on-disk vector data 2751 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2752 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2753 - vec - The local vector to set values of 2754 2755 Level: advanced 2756 2757 Notes: 2758 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. 2759 2760 Calling sequence: 2761 .vb 2762 DMCreate(PETSC_COMM_WORLD, &dm); 2763 DMSetType(dm, DMPLEX); 2764 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2765 DMPlexTopologyLoad(dm, viewer, &sfX); 2766 DMClone(dm, §iondm); 2767 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2768 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2769 DMGetLocalVector(sectiondm, &vec); 2770 PetscObjectSetName((PetscObject)vec, "vec_name"); 2771 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2772 DMRestoreLocalVector(sectiondm, &vec); 2773 PetscSFDestroy(&lsf); 2774 PetscSFDestroy(&sfX); 2775 DMDestroy(§iondm); 2776 DMDestroy(&dm); 2777 .ve 2778 2779 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2780 `PetscSF`, `PetscViewer` 2781 @*/ 2782 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2783 { 2784 PetscBool ishdf5; 2785 2786 PetscFunctionBegin; 2787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2788 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2789 if (!sectiondm) sectiondm = dm; 2790 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2791 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2792 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2793 /* Check consistency */ 2794 { 2795 PetscSection section; 2796 PetscBool includesConstraints; 2797 PetscInt m, m1; 2798 2799 PetscCall(VecGetLocalSize(vec, &m1)); 2800 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2801 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2802 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2803 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2804 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2805 } 2806 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2807 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2808 if (ishdf5) { 2809 #if defined(PETSC_HAVE_HDF5) 2810 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2811 #else 2812 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2813 #endif 2814 } 2815 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2816 PetscFunctionReturn(PETSC_SUCCESS); 2817 } 2818 2819 PetscErrorCode DMDestroy_Plex(DM dm) 2820 { 2821 DM_Plex *mesh = (DM_Plex *)dm->data; 2822 2823 PetscFunctionBegin; 2824 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2825 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2826 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2827 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBounds_C", NULL)); 2828 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2829 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2830 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2831 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2832 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2833 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2834 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2835 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2836 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2837 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2838 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2839 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2840 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2841 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2842 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2843 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2844 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2845 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2846 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2847 PetscCall(PetscFree(mesh->cones)); 2848 PetscCall(PetscFree(mesh->coneOrientations)); 2849 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2850 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2851 PetscCall(PetscFree(mesh->supports)); 2852 PetscCall(PetscFree(mesh->cellTypes)); 2853 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2854 PetscCall(PetscFree(mesh->tetgenOpts)); 2855 PetscCall(PetscFree(mesh->triangleOpts)); 2856 PetscCall(PetscFree(mesh->transformType)); 2857 PetscCall(PetscFree(mesh->distributionName)); 2858 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2859 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2860 PetscCall(ISDestroy(&mesh->subpointIS)); 2861 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2862 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2863 if (mesh->periodic.face_sfs) { 2864 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2865 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2866 } 2867 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2868 if (mesh->periodic.periodic_points) { 2869 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2870 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2871 } 2872 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2873 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2874 PetscCall(ISDestroy(&mesh->anchorIS)); 2875 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2876 PetscCall(PetscFree(mesh->parents)); 2877 PetscCall(PetscFree(mesh->childIDs)); 2878 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2879 PetscCall(PetscFree(mesh->children)); 2880 PetscCall(DMDestroy(&mesh->referenceTree)); 2881 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2882 PetscCall(PetscFree(mesh->neighbors)); 2883 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2884 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2885 PetscCall(DMPlexTransformDestroy(&mesh->transform)); 2886 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2887 PetscCall(PetscFree(mesh)); 2888 PetscFunctionReturn(PETSC_SUCCESS); 2889 } 2890 2891 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2892 { 2893 PetscSection sectionGlobal, sectionLocal; 2894 PetscInt bs = -1, mbs; 2895 PetscInt localSize, localStart = 0; 2896 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2897 MatType mtype; 2898 ISLocalToGlobalMapping ltog; 2899 2900 PetscFunctionBegin; 2901 PetscCall(MatInitializePackage()); 2902 mtype = dm->mattype; 2903 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2904 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2905 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2906 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2907 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2908 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2909 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2910 PetscCall(MatSetType(*J, mtype)); 2911 PetscCall(MatSetFromOptions(*J)); 2912 PetscCall(MatGetBlockSize(*J, &mbs)); 2913 if (mbs > 1) bs = mbs; 2914 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2915 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2916 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2917 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2918 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2919 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2920 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2921 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2922 if (!isShell) { 2923 // There are three states with pblocks, since block starts can have no dofs: 2924 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2925 // TRUE) Block Start: The first entry in a block has been added 2926 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2927 PetscBT blst; 2928 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2929 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2930 const PetscInt *perm = NULL; 2931 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2932 PetscInt pStart, pEnd, dof, cdof, num_fields; 2933 2934 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2935 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2936 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2937 2938 PetscCall(PetscCalloc1(localSize, &pblocks)); 2939 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2940 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2941 // We need to process in the permuted order to get block sizes right 2942 for (PetscInt point = pStart; point < pEnd; ++point) { 2943 const PetscInt p = perm ? perm[point] : point; 2944 2945 switch (dm->blocking_type) { 2946 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2947 PetscInt bdof, offset; 2948 2949 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2950 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2951 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2952 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2953 if (dof > 0) { 2954 // State change 2955 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2956 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2957 2958 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2959 // Signal block concatenation 2960 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2961 } 2962 dof = dof < 0 ? -(dof + 1) : dof; 2963 bdof = cdof && (dof - cdof) ? 1 : dof; 2964 if (dof) { 2965 if (bs < 0) { 2966 bs = bdof; 2967 } else if (bs != bdof) { 2968 bs = 1; 2969 } 2970 } 2971 } break; 2972 case DM_BLOCKING_FIELD_NODE: { 2973 for (PetscInt field = 0; field < num_fields; field++) { 2974 PetscInt num_comp, bdof, offset; 2975 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2976 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2977 if (dof < 0) continue; 2978 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2979 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2980 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); 2981 PetscInt num_nodes = dof / num_comp; 2982 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2983 // Handle possibly constant block size (unlikely) 2984 bdof = cdof && (dof - cdof) ? 1 : dof; 2985 if (dof) { 2986 if (bs < 0) { 2987 bs = bdof; 2988 } else if (bs != bdof) { 2989 bs = 1; 2990 } 2991 } 2992 } 2993 } break; 2994 } 2995 } 2996 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2997 /* Must have same blocksize on all procs (some might have no points) */ 2998 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 2999 bsLocal[1] = bs; 3000 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 3001 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 3002 else bs = bsMinMax[0]; 3003 bs = PetscMax(1, bs); 3004 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 3005 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 3006 PetscCall(MatSetBlockSize(*J, bs)); 3007 PetscCall(MatSetUp(*J)); 3008 } else { 3009 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 3010 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 3011 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 3012 } 3013 if (pblocks) { // Consolidate blocks 3014 PetscInt nblocks = 0; 3015 pblocks[0] = PetscAbs(pblocks[0]); 3016 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 3017 if (pblocks[i] == 0) continue; 3018 // Negative block size indicates the blocks should be concatenated 3019 if (pblocks[i] < 0) { 3020 pblocks[i] = -pblocks[i]; 3021 pblocks[nblocks - 1] += pblocks[i]; 3022 } else { 3023 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 3024 } 3025 for (PetscInt j = 1; j < pblocks[i]; j++) 3026 PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j); 3027 } 3028 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 3029 } 3030 PetscCall(PetscFree(pblocks)); 3031 } 3032 PetscCall(MatSetDM(*J, dm)); 3033 PetscFunctionReturn(PETSC_SUCCESS); 3034 } 3035 3036 /*@ 3037 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 3038 3039 Not Collective 3040 3041 Input Parameter: 3042 . dm - The `DMPLEX` 3043 3044 Output Parameter: 3045 . subsection - The subdomain section 3046 3047 Level: developer 3048 3049 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 3050 @*/ 3051 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 3052 { 3053 DM_Plex *mesh = (DM_Plex *)dm->data; 3054 3055 PetscFunctionBegin; 3056 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3057 if (!mesh->subdomainSection) { 3058 PetscSection section; 3059 PetscSF sf; 3060 3061 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 3062 PetscCall(DMGetLocalSection(dm, §ion)); 3063 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 3064 PetscCall(PetscSFDestroy(&sf)); 3065 } 3066 *subsection = mesh->subdomainSection; 3067 PetscFunctionReturn(PETSC_SUCCESS); 3068 } 3069 3070 /*@ 3071 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 3072 3073 Not Collective 3074 3075 Input Parameter: 3076 . dm - The `DMPLEX` 3077 3078 Output Parameters: 3079 + pStart - The first mesh point 3080 - pEnd - The upper bound for mesh points 3081 3082 Level: beginner 3083 3084 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3085 @*/ 3086 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3087 { 3088 DM_Plex *mesh = (DM_Plex *)dm->data; 3089 3090 PetscFunctionBegin; 3091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3092 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3093 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3094 PetscFunctionReturn(PETSC_SUCCESS); 3095 } 3096 3097 /*@ 3098 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3099 3100 Not Collective 3101 3102 Input Parameters: 3103 + dm - The `DMPLEX` 3104 . pStart - The first mesh point 3105 - pEnd - The upper bound for mesh points 3106 3107 Level: beginner 3108 3109 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3110 @*/ 3111 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3112 { 3113 DM_Plex *mesh = (DM_Plex *)dm->data; 3114 3115 PetscFunctionBegin; 3116 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3117 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3118 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3119 PetscCall(PetscFree(mesh->cellTypes)); 3120 PetscFunctionReturn(PETSC_SUCCESS); 3121 } 3122 3123 /*@ 3124 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3125 3126 Not Collective 3127 3128 Input Parameters: 3129 + dm - The `DMPLEX` 3130 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3131 3132 Output Parameter: 3133 . size - The cone size for point `p` 3134 3135 Level: beginner 3136 3137 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3138 @*/ 3139 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3140 { 3141 DM_Plex *mesh = (DM_Plex *)dm->data; 3142 3143 PetscFunctionBegin; 3144 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3145 PetscAssertPointer(size, 3); 3146 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3147 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3148 PetscFunctionReturn(PETSC_SUCCESS); 3149 } 3150 3151 /*@ 3152 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3153 3154 Not Collective 3155 3156 Input Parameters: 3157 + dm - The `DMPLEX` 3158 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3159 - size - The cone size for point `p` 3160 3161 Level: beginner 3162 3163 Note: 3164 This should be called after `DMPlexSetChart()`. 3165 3166 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3167 @*/ 3168 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3169 { 3170 DM_Plex *mesh = (DM_Plex *)dm->data; 3171 3172 PetscFunctionBegin; 3173 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3174 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3175 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3176 PetscFunctionReturn(PETSC_SUCCESS); 3177 } 3178 3179 /*@C 3180 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3181 3182 Not Collective 3183 3184 Input Parameters: 3185 + dm - The `DMPLEX` 3186 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3187 3188 Output Parameter: 3189 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3190 3191 Level: beginner 3192 3193 Fortran Notes: 3194 `cone` must be declared with 3195 .vb 3196 PetscInt, pointer :: cone(:) 3197 .ve 3198 3199 You must call `DMPlexRestoreCone()` after you finish using the array. 3200 `DMPlexRestoreCone()` is not needed/available in C. 3201 3202 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3203 @*/ 3204 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3205 { 3206 DM_Plex *mesh = (DM_Plex *)dm->data; 3207 PetscInt off; 3208 3209 PetscFunctionBegin; 3210 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3211 PetscAssertPointer(cone, 3); 3212 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3213 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3214 PetscFunctionReturn(PETSC_SUCCESS); 3215 } 3216 3217 /*@ 3218 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3219 3220 Not Collective 3221 3222 Input Parameters: 3223 + dm - The `DMPLEX` 3224 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3225 3226 Output Parameters: 3227 + pConesSection - `PetscSection` describing the layout of `pCones` 3228 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3229 3230 Level: intermediate 3231 3232 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3233 @*/ 3234 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PeOp PetscSection *pConesSection, PeOp IS *pCones) 3235 { 3236 PetscSection cs, newcs; 3237 PetscInt *cones; 3238 PetscInt *newarr = NULL; 3239 PetscInt n; 3240 3241 PetscFunctionBegin; 3242 PetscCall(DMPlexGetCones(dm, &cones)); 3243 PetscCall(DMPlexGetConeSection(dm, &cs)); 3244 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3245 if (pConesSection) *pConesSection = newcs; 3246 if (pCones) { 3247 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3248 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3249 } 3250 PetscFunctionReturn(PETSC_SUCCESS); 3251 } 3252 3253 /*@ 3254 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3255 3256 Not Collective 3257 3258 Input Parameters: 3259 + dm - The `DMPLEX` 3260 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3261 3262 Output Parameter: 3263 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3264 3265 Level: advanced 3266 3267 Notes: 3268 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3269 3270 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3271 3272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3273 `DMPlexGetDepth()`, `IS` 3274 @*/ 3275 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3276 { 3277 IS *expandedPointsAll; 3278 PetscInt depth; 3279 3280 PetscFunctionBegin; 3281 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3282 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3283 PetscAssertPointer(expandedPoints, 3); 3284 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3285 *expandedPoints = expandedPointsAll[0]; 3286 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3287 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3288 PetscFunctionReturn(PETSC_SUCCESS); 3289 } 3290 3291 /*@ 3292 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3293 (DAG points of depth 0, i.e., without cones). 3294 3295 Not Collective 3296 3297 Input Parameters: 3298 + dm - The `DMPLEX` 3299 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3300 3301 Output Parameters: 3302 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3303 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3304 - sections - (optional) An array of sections which describe mappings from points to their cone points 3305 3306 Level: advanced 3307 3308 Notes: 3309 Like `DMPlexGetConeTuple()` but recursive. 3310 3311 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. 3312 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3313 3314 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\: 3315 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3316 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3317 3318 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3319 `DMPlexGetDepth()`, `PetscSection`, `IS` 3320 @*/ 3321 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3322 { 3323 const PetscInt *arr0 = NULL, *cone = NULL; 3324 PetscInt *arr = NULL, *newarr = NULL; 3325 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3326 IS *expandedPoints_; 3327 PetscSection *sections_; 3328 3329 PetscFunctionBegin; 3330 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3331 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3332 if (depth) PetscAssertPointer(depth, 3); 3333 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3334 if (sections) PetscAssertPointer(sections, 5); 3335 PetscCall(ISGetLocalSize(points, &n)); 3336 PetscCall(ISGetIndices(points, &arr0)); 3337 PetscCall(DMPlexGetDepth(dm, &depth_)); 3338 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3339 PetscCall(PetscCalloc1(depth_, §ions_)); 3340 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3341 for (d = depth_ - 1; d >= 0; d--) { 3342 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3343 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3344 for (i = 0; i < n; i++) { 3345 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3346 if (arr[i] >= start && arr[i] < end) { 3347 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3348 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3349 } else { 3350 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3351 } 3352 } 3353 PetscCall(PetscSectionSetUp(sections_[d])); 3354 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3355 PetscCall(PetscMalloc1(newn, &newarr)); 3356 for (i = 0; i < n; i++) { 3357 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3358 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3359 if (cn > 1) { 3360 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3361 PetscCall(PetscArraycpy(&newarr[co], cone, cn)); 3362 } else { 3363 newarr[co] = arr[i]; 3364 } 3365 } 3366 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3367 arr = newarr; 3368 n = newn; 3369 } 3370 PetscCall(ISRestoreIndices(points, &arr0)); 3371 *depth = depth_; 3372 if (expandedPoints) *expandedPoints = expandedPoints_; 3373 else { 3374 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3375 PetscCall(PetscFree(expandedPoints_)); 3376 } 3377 if (sections) *sections = sections_; 3378 else { 3379 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3380 PetscCall(PetscFree(sections_)); 3381 } 3382 PetscFunctionReturn(PETSC_SUCCESS); 3383 } 3384 3385 /*@ 3386 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3387 3388 Not Collective 3389 3390 Input Parameters: 3391 + dm - The `DMPLEX` 3392 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3393 3394 Output Parameters: 3395 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3396 . expandedPoints - (optional) An array of recursively expanded cones 3397 - sections - (optional) An array of sections which describe mappings from points to their cone points 3398 3399 Level: advanced 3400 3401 Note: 3402 See `DMPlexGetConeRecursive()` 3403 3404 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3405 `DMPlexGetDepth()`, `IS`, `PetscSection` 3406 @*/ 3407 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3408 { 3409 PetscInt d, depth_; 3410 3411 PetscFunctionBegin; 3412 PetscCall(DMPlexGetDepth(dm, &depth_)); 3413 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3414 if (depth) *depth = 0; 3415 if (expandedPoints) { 3416 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3417 PetscCall(PetscFree(*expandedPoints)); 3418 } 3419 if (sections) { 3420 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3421 PetscCall(PetscFree(*sections)); 3422 } 3423 PetscFunctionReturn(PETSC_SUCCESS); 3424 } 3425 3426 /*@ 3427 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 3428 3429 Not Collective 3430 3431 Input Parameters: 3432 + dm - The `DMPLEX` 3433 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3434 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3435 3436 Level: beginner 3437 3438 Note: 3439 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3440 3441 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3442 @*/ 3443 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3444 { 3445 DM_Plex *mesh = (DM_Plex *)dm->data; 3446 PetscInt dof, off, c; 3447 3448 PetscFunctionBegin; 3449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3450 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3451 if (dof) PetscAssertPointer(cone, 3); 3452 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3453 if (PetscDefined(USE_DEBUG)) { 3454 PetscInt pStart, pEnd; 3455 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3456 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); 3457 for (c = 0; c < dof; ++c) { 3458 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); 3459 mesh->cones[off + c] = cone[c]; 3460 } 3461 } else { 3462 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3463 } 3464 PetscFunctionReturn(PETSC_SUCCESS); 3465 } 3466 3467 /*@C 3468 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3469 3470 Not Collective 3471 3472 Input Parameters: 3473 + dm - The `DMPLEX` 3474 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3475 3476 Output Parameter: 3477 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3478 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3479 3480 Level: beginner 3481 3482 Note: 3483 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3484 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3485 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3486 with the identity. 3487 3488 Fortran Notes: 3489 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3490 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3491 3492 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3493 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3494 @*/ 3495 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3496 { 3497 DM_Plex *mesh = (DM_Plex *)dm->data; 3498 PetscInt off; 3499 3500 PetscFunctionBegin; 3501 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3502 if (PetscDefined(USE_DEBUG)) { 3503 PetscInt dof; 3504 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3505 if (dof) PetscAssertPointer(coneOrientation, 3); 3506 } 3507 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3508 3509 *coneOrientation = &mesh->coneOrientations[off]; 3510 PetscFunctionReturn(PETSC_SUCCESS); 3511 } 3512 3513 /*@ 3514 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3515 3516 Not Collective 3517 3518 Input Parameters: 3519 + dm - The `DMPLEX` 3520 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3521 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3522 3523 Level: beginner 3524 3525 Notes: 3526 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3527 3528 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3529 3530 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3531 @*/ 3532 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3533 { 3534 DM_Plex *mesh = (DM_Plex *)dm->data; 3535 PetscInt pStart, pEnd; 3536 PetscInt dof, off, c; 3537 3538 PetscFunctionBegin; 3539 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3540 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3541 if (dof) PetscAssertPointer(coneOrientation, 3); 3542 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3543 if (PetscDefined(USE_DEBUG)) { 3544 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3545 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); 3546 for (c = 0; c < dof; ++c) { 3547 PetscInt cdof, o = coneOrientation[c]; 3548 3549 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3550 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); 3551 mesh->coneOrientations[off + c] = o; 3552 } 3553 } else { 3554 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3555 } 3556 PetscFunctionReturn(PETSC_SUCCESS); 3557 } 3558 3559 /*@ 3560 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3561 3562 Not Collective 3563 3564 Input Parameters: 3565 + dm - The `DMPLEX` 3566 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3567 . conePos - The local index in the cone where the point should be put 3568 - conePoint - The mesh point to insert 3569 3570 Level: beginner 3571 3572 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3573 @*/ 3574 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3575 { 3576 DM_Plex *mesh = (DM_Plex *)dm->data; 3577 PetscInt pStart, pEnd; 3578 PetscInt dof, off; 3579 3580 PetscFunctionBegin; 3581 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3582 if (PetscDefined(USE_DEBUG)) { 3583 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3584 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); 3585 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); 3586 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3587 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); 3588 } 3589 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3590 mesh->cones[off + conePos] = conePoint; 3591 PetscFunctionReturn(PETSC_SUCCESS); 3592 } 3593 3594 /*@ 3595 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3596 3597 Not Collective 3598 3599 Input Parameters: 3600 + dm - The `DMPLEX` 3601 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3602 . conePos - The local index in the cone where the point should be put 3603 - coneOrientation - The point orientation to insert 3604 3605 Level: beginner 3606 3607 Note: 3608 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3609 3610 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3611 @*/ 3612 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3613 { 3614 DM_Plex *mesh = (DM_Plex *)dm->data; 3615 PetscInt pStart, pEnd; 3616 PetscInt dof, off; 3617 3618 PetscFunctionBegin; 3619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3620 if (PetscDefined(USE_DEBUG)) { 3621 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3622 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); 3623 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3624 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); 3625 } 3626 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3627 mesh->coneOrientations[off + conePos] = coneOrientation; 3628 PetscFunctionReturn(PETSC_SUCCESS); 3629 } 3630 3631 /*@C 3632 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3633 3634 Not collective 3635 3636 Input Parameters: 3637 + dm - The DMPlex 3638 - p - The point, which must lie in the chart set with DMPlexSetChart() 3639 3640 Output Parameters: 3641 + cone - An array of points which are on the in-edges for point `p` 3642 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3643 integer giving the prescription for cone traversal. 3644 3645 Level: beginner 3646 3647 Notes: 3648 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3649 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3650 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3651 with the identity. 3652 3653 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3654 3655 Fortran Notes: 3656 `cone` and `ornt` must be declared with 3657 .vb 3658 PetscInt, pointer :: cone(:) 3659 PetscInt, pointer :: ornt(:) 3660 .ve 3661 3662 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3663 @*/ 3664 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, PeOp const PetscInt *cone[], PeOp const PetscInt *ornt[]) 3665 { 3666 DM_Plex *mesh = (DM_Plex *)dm->data; 3667 3668 PetscFunctionBegin; 3669 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3670 if (mesh->tr) { 3671 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3672 } else { 3673 PetscInt off; 3674 if (PetscDefined(USE_DEBUG)) { 3675 PetscInt dof; 3676 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3677 if (dof) { 3678 if (cone) PetscAssertPointer(cone, 3); 3679 if (ornt) PetscAssertPointer(ornt, 4); 3680 } 3681 } 3682 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3683 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3684 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3685 } 3686 PetscFunctionReturn(PETSC_SUCCESS); 3687 } 3688 3689 /*@C 3690 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3691 3692 Not Collective 3693 3694 Input Parameters: 3695 + dm - The DMPlex 3696 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3697 . cone - An array of points which are on the in-edges for point p 3698 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3699 integer giving the prescription for cone traversal. 3700 3701 Level: beginner 3702 3703 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3704 @*/ 3705 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3706 { 3707 DM_Plex *mesh = (DM_Plex *)dm->data; 3708 3709 PetscFunctionBegin; 3710 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3711 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3712 PetscFunctionReturn(PETSC_SUCCESS); 3713 } 3714 3715 /*@ 3716 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3717 3718 Not Collective 3719 3720 Input Parameters: 3721 + dm - The `DMPLEX` 3722 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3723 3724 Output Parameter: 3725 . size - The support size for point `p` 3726 3727 Level: beginner 3728 3729 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3730 @*/ 3731 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3732 { 3733 DM_Plex *mesh = (DM_Plex *)dm->data; 3734 3735 PetscFunctionBegin; 3736 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3737 PetscAssertPointer(size, 3); 3738 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3739 PetscFunctionReturn(PETSC_SUCCESS); 3740 } 3741 3742 /*@ 3743 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3744 3745 Not Collective 3746 3747 Input Parameters: 3748 + dm - The `DMPLEX` 3749 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3750 - size - The support size for point `p` 3751 3752 Level: beginner 3753 3754 Note: 3755 This should be called after `DMPlexSetChart()`. 3756 3757 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3758 @*/ 3759 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3760 { 3761 DM_Plex *mesh = (DM_Plex *)dm->data; 3762 3763 PetscFunctionBegin; 3764 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3765 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3766 PetscFunctionReturn(PETSC_SUCCESS); 3767 } 3768 3769 /*@C 3770 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3771 3772 Not Collective 3773 3774 Input Parameters: 3775 + dm - The `DMPLEX` 3776 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3777 3778 Output Parameter: 3779 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3780 3781 Level: beginner 3782 3783 Fortran Notes: 3784 `support` must be declared with 3785 .vb 3786 PetscInt, pointer :: support(:) 3787 .ve 3788 3789 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3790 `DMPlexRestoreSupport()` is not needed/available in C. 3791 3792 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3793 @*/ 3794 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3795 { 3796 DM_Plex *mesh = (DM_Plex *)dm->data; 3797 PetscInt off; 3798 3799 PetscFunctionBegin; 3800 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3801 PetscAssertPointer(support, 3); 3802 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3803 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3804 PetscFunctionReturn(PETSC_SUCCESS); 3805 } 3806 3807 /*@ 3808 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3809 3810 Not Collective 3811 3812 Input Parameters: 3813 + dm - The `DMPLEX` 3814 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3815 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3816 3817 Level: beginner 3818 3819 Note: 3820 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3821 3822 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3823 @*/ 3824 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3825 { 3826 DM_Plex *mesh = (DM_Plex *)dm->data; 3827 PetscInt pStart, pEnd; 3828 PetscInt dof, off, c; 3829 3830 PetscFunctionBegin; 3831 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3832 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3833 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3834 if (dof) PetscAssertPointer(support, 3); 3835 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3836 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); 3837 for (c = 0; c < dof; ++c) { 3838 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); 3839 mesh->supports[off + c] = support[c]; 3840 } 3841 PetscFunctionReturn(PETSC_SUCCESS); 3842 } 3843 3844 /*@ 3845 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3846 3847 Not Collective 3848 3849 Input Parameters: 3850 + dm - The `DMPLEX` 3851 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3852 . supportPos - The local index in the cone where the point should be put 3853 - supportPoint - The mesh point to insert 3854 3855 Level: beginner 3856 3857 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3858 @*/ 3859 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3860 { 3861 DM_Plex *mesh = (DM_Plex *)dm->data; 3862 PetscInt pStart, pEnd; 3863 PetscInt dof, off; 3864 3865 PetscFunctionBegin; 3866 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3867 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3868 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3869 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3870 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); 3871 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); 3872 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); 3873 mesh->supports[off + supportPos] = supportPoint; 3874 PetscFunctionReturn(PETSC_SUCCESS); 3875 } 3876 3877 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3878 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3879 { 3880 switch (ct) { 3881 case DM_POLYTOPE_SEGMENT: 3882 if (o == -1) return -2; 3883 break; 3884 case DM_POLYTOPE_TRIANGLE: 3885 if (o == -3) return -1; 3886 if (o == -2) return -3; 3887 if (o == -1) return -2; 3888 break; 3889 case DM_POLYTOPE_QUADRILATERAL: 3890 if (o == -4) return -2; 3891 if (o == -3) return -1; 3892 if (o == -2) return -4; 3893 if (o == -1) return -3; 3894 break; 3895 default: 3896 return o; 3897 } 3898 return o; 3899 } 3900 3901 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3902 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3903 { 3904 switch (ct) { 3905 case DM_POLYTOPE_SEGMENT: 3906 if ((o == -2) || (o == 1)) return -1; 3907 if (o == -1) return 0; 3908 break; 3909 case DM_POLYTOPE_TRIANGLE: 3910 if (o == -3) return -2; 3911 if (o == -2) return -1; 3912 if (o == -1) return -3; 3913 break; 3914 case DM_POLYTOPE_QUADRILATERAL: 3915 if (o == -4) return -2; 3916 if (o == -3) return -1; 3917 if (o == -2) return -4; 3918 if (o == -1) return -3; 3919 break; 3920 default: 3921 return o; 3922 } 3923 return o; 3924 } 3925 3926 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3927 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3928 { 3929 PetscInt pStart, pEnd, p; 3930 3931 PetscFunctionBegin; 3932 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3933 for (p = pStart; p < pEnd; ++p) { 3934 const PetscInt *cone, *ornt; 3935 PetscInt coneSize, c; 3936 3937 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3938 PetscCall(DMPlexGetCone(dm, p, &cone)); 3939 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3940 for (c = 0; c < coneSize; ++c) { 3941 DMPolytopeType ct; 3942 const PetscInt o = ornt[c]; 3943 3944 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3945 switch (ct) { 3946 case DM_POLYTOPE_SEGMENT: 3947 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3948 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3949 break; 3950 case DM_POLYTOPE_TRIANGLE: 3951 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3952 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3953 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3954 break; 3955 case DM_POLYTOPE_QUADRILATERAL: 3956 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3957 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3958 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3959 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3960 break; 3961 default: 3962 break; 3963 } 3964 } 3965 } 3966 PetscFunctionReturn(PETSC_SUCCESS); 3967 } 3968 3969 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3970 { 3971 DM_Plex *mesh = (DM_Plex *)dm->data; 3972 3973 PetscFunctionBeginHot; 3974 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3975 if (useCone) { 3976 PetscCall(DMPlexGetConeSize(dm, p, size)); 3977 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3978 } else { 3979 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3980 PetscCall(DMPlexGetSupport(dm, p, arr)); 3981 } 3982 } else { 3983 if (useCone) { 3984 const PetscSection s = mesh->coneSection; 3985 const PetscInt ps = p - s->pStart; 3986 const PetscInt off = s->atlasOff[ps]; 3987 3988 *size = s->atlasDof[ps]; 3989 *arr = mesh->cones + off; 3990 *ornt = mesh->coneOrientations + off; 3991 } else { 3992 const PetscSection s = mesh->supportSection; 3993 const PetscInt ps = p - s->pStart; 3994 const PetscInt off = s->atlasOff[ps]; 3995 3996 *size = s->atlasDof[ps]; 3997 *arr = mesh->supports + off; 3998 } 3999 } 4000 PetscFunctionReturn(PETSC_SUCCESS); 4001 } 4002 4003 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 4004 { 4005 DM_Plex *mesh = (DM_Plex *)dm->data; 4006 4007 PetscFunctionBeginHot; 4008 if (PetscDefined(USE_DEBUG) || mesh->tr) { 4009 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 4010 } 4011 PetscFunctionReturn(PETSC_SUCCESS); 4012 } 4013 4014 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4015 { 4016 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4017 PetscInt *closure; 4018 const PetscInt *tmp = NULL, *tmpO = NULL; 4019 PetscInt off = 0, tmpSize, t; 4020 4021 PetscFunctionBeginHot; 4022 if (ornt) { 4023 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4024 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 4025 } 4026 if (*points) { 4027 closure = *points; 4028 } else { 4029 PetscInt maxConeSize, maxSupportSize; 4030 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4031 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 4032 } 4033 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4034 if (ct == DM_POLYTOPE_UNKNOWN) { 4035 closure[off++] = p; 4036 closure[off++] = 0; 4037 for (t = 0; t < tmpSize; ++t) { 4038 closure[off++] = tmp[t]; 4039 closure[off++] = tmpO ? tmpO[t] : 0; 4040 } 4041 } else { 4042 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 4043 4044 /* We assume that cells with a valid type have faces with a valid type */ 4045 closure[off++] = p; 4046 closure[off++] = ornt; 4047 for (t = 0; t < tmpSize; ++t) { 4048 DMPolytopeType ft; 4049 4050 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 4051 closure[off++] = tmp[arr[t]]; 4052 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 4053 } 4054 } 4055 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4056 if (numPoints) *numPoints = tmpSize + 1; 4057 if (points) *points = closure; 4058 PetscFunctionReturn(PETSC_SUCCESS); 4059 } 4060 4061 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 4062 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 4063 { 4064 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 4065 const PetscInt *cone, *ornt; 4066 PetscInt *pts, *closure = NULL; 4067 DMPolytopeType ft; 4068 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 4069 PetscInt dim, coneSize, c, d, clSize, cl; 4070 4071 PetscFunctionBeginHot; 4072 PetscCall(DMGetDimension(dm, &dim)); 4073 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4074 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4075 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4076 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4077 maxSize = PetscMax(coneSeries, supportSeries); 4078 if (*points) { 4079 pts = *points; 4080 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4081 c = 0; 4082 pts[c++] = point; 4083 pts[c++] = o; 4084 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4085 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4086 for (cl = 0; cl < clSize * 2; cl += 2) { 4087 pts[c++] = closure[cl]; 4088 pts[c++] = closure[cl + 1]; 4089 } 4090 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4091 for (cl = 0; cl < clSize * 2; cl += 2) { 4092 pts[c++] = closure[cl]; 4093 pts[c++] = closure[cl + 1]; 4094 } 4095 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4096 for (d = 2; d < coneSize; ++d) { 4097 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4098 pts[c++] = cone[arr[d * 2 + 0]]; 4099 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4100 } 4101 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4102 if (dim >= 3) { 4103 for (d = 2; d < coneSize; ++d) { 4104 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4105 const PetscInt *fcone, *fornt; 4106 PetscInt fconeSize, fc, i; 4107 4108 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4109 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4110 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4111 for (fc = 0; fc < fconeSize; ++fc) { 4112 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4113 const PetscInt co = farr[fc * 2 + 1]; 4114 4115 for (i = 0; i < c; i += 2) 4116 if (pts[i] == cp) break; 4117 if (i == c) { 4118 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4119 pts[c++] = cp; 4120 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4121 } 4122 } 4123 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4124 } 4125 } 4126 *numPoints = c / 2; 4127 *points = pts; 4128 PetscFunctionReturn(PETSC_SUCCESS); 4129 } 4130 4131 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4132 { 4133 DMPolytopeType ct; 4134 PetscInt *closure, *fifo; 4135 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4136 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4137 PetscInt depth, maxSize; 4138 4139 PetscFunctionBeginHot; 4140 PetscCall(DMPlexGetDepth(dm, &depth)); 4141 if (depth == 1) { 4142 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4143 PetscFunctionReturn(PETSC_SUCCESS); 4144 } 4145 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4146 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; 4147 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4148 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4149 PetscFunctionReturn(PETSC_SUCCESS); 4150 } 4151 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4152 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4153 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4154 maxSize = PetscMax(coneSeries, supportSeries); 4155 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4156 if (*points) { 4157 closure = *points; 4158 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4159 closure[closureSize++] = p; 4160 closure[closureSize++] = ornt; 4161 fifo[fifoSize++] = p; 4162 fifo[fifoSize++] = ornt; 4163 fifo[fifoSize++] = ct; 4164 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4165 while (fifoSize - fifoStart) { 4166 const PetscInt q = fifo[fifoStart++]; 4167 const PetscInt o = fifo[fifoStart++]; 4168 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4169 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4170 const PetscInt *tmp, *tmpO = NULL; 4171 PetscInt tmpSize, t; 4172 4173 if (PetscDefined(USE_DEBUG)) { 4174 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4175 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); 4176 } 4177 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4178 for (t = 0; t < tmpSize; ++t) { 4179 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4180 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4181 const PetscInt cp = tmp[ip]; 4182 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4183 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4184 PetscInt c; 4185 4186 /* Check for duplicate */ 4187 for (c = 0; c < closureSize; c += 2) { 4188 if (closure[c] == cp) break; 4189 } 4190 if (c == closureSize) { 4191 closure[closureSize++] = cp; 4192 closure[closureSize++] = co; 4193 fifo[fifoSize++] = cp; 4194 fifo[fifoSize++] = co; 4195 fifo[fifoSize++] = ct; 4196 } 4197 } 4198 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4199 } 4200 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4201 if (numPoints) *numPoints = closureSize / 2; 4202 if (points) *points = closure; 4203 PetscFunctionReturn(PETSC_SUCCESS); 4204 } 4205 4206 /*@C 4207 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4208 4209 Not Collective 4210 4211 Input Parameters: 4212 + dm - The `DMPLEX` 4213 . p - The mesh point 4214 - useCone - `PETSC_TRUE` for the closure, otherwise return the support 4215 4216 Input/Output Parameter: 4217 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4218 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4219 otherwise the provided array is used to hold the values 4220 4221 Output Parameter: 4222 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4223 4224 Level: beginner 4225 4226 Note: 4227 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4228 4229 Fortran Notes: 4230 `points` must be declared with 4231 .vb 4232 PetscInt, pointer :: points(:) 4233 .ve 4234 and is always allocated by the function. 4235 4236 Pass `PETSC_NULL_INTEGER` for `numPoints` if it is not needed 4237 4238 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4239 @*/ 4240 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4241 { 4242 PetscFunctionBeginHot; 4243 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4244 if (numPoints) PetscAssertPointer(numPoints, 4); 4245 if (points) PetscAssertPointer(points, 5); 4246 if (PetscDefined(USE_DEBUG)) { 4247 PetscInt pStart, pEnd; 4248 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4249 PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 4250 } 4251 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4252 PetscFunctionReturn(PETSC_SUCCESS); 4253 } 4254 4255 /*@C 4256 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4257 4258 Not Collective 4259 4260 Input Parameters: 4261 + dm - The `DMPLEX` 4262 . p - The mesh point 4263 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4264 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4265 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4266 4267 Level: beginner 4268 4269 Note: 4270 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4271 4272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4273 @*/ 4274 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4275 { 4276 PetscFunctionBeginHot; 4277 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4278 if (numPoints) *numPoints = 0; 4279 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4280 PetscFunctionReturn(PETSC_SUCCESS); 4281 } 4282 4283 /*@ 4284 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4285 4286 Not Collective 4287 4288 Input Parameter: 4289 . dm - The `DMPLEX` 4290 4291 Output Parameters: 4292 + maxConeSize - The maximum number of in-edges 4293 - maxSupportSize - The maximum number of out-edges 4294 4295 Level: beginner 4296 4297 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4298 @*/ 4299 PetscErrorCode DMPlexGetMaxSizes(DM dm, PeOp PetscInt *maxConeSize, PeOp PetscInt *maxSupportSize) 4300 { 4301 DM_Plex *mesh = (DM_Plex *)dm->data; 4302 4303 PetscFunctionBegin; 4304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4305 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4306 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4307 PetscFunctionReturn(PETSC_SUCCESS); 4308 } 4309 4310 PetscErrorCode DMSetUp_Plex(DM dm) 4311 { 4312 DM_Plex *mesh = (DM_Plex *)dm->data; 4313 PetscInt size, maxSupportSize; 4314 4315 PetscFunctionBegin; 4316 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4317 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4318 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4319 PetscCall(PetscMalloc1(size, &mesh->cones)); 4320 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4321 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4322 if (maxSupportSize) { 4323 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4324 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4325 PetscCall(PetscMalloc1(size, &mesh->supports)); 4326 } 4327 PetscFunctionReturn(PETSC_SUCCESS); 4328 } 4329 4330 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4331 { 4332 PetscFunctionBegin; 4333 if (subdm) PetscCall(DMClone(dm, subdm)); 4334 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4335 if (subdm) (*subdm)->useNatural = dm->useNatural; 4336 if (dm->useNatural && dm->sfMigration) { 4337 PetscSF sfNatural; 4338 4339 (*subdm)->sfMigration = dm->sfMigration; 4340 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4341 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4342 (*subdm)->sfNatural = sfNatural; 4343 } 4344 PetscFunctionReturn(PETSC_SUCCESS); 4345 } 4346 4347 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4348 { 4349 PetscInt i = 0; 4350 4351 PetscFunctionBegin; 4352 PetscCall(DMClone(dms[0], superdm)); 4353 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4354 (*superdm)->useNatural = PETSC_FALSE; 4355 for (i = 0; i < len; i++) { 4356 if (dms[i]->useNatural && dms[i]->sfMigration) { 4357 PetscSF sfNatural; 4358 4359 (*superdm)->sfMigration = dms[i]->sfMigration; 4360 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4361 (*superdm)->useNatural = PETSC_TRUE; 4362 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4363 (*superdm)->sfNatural = sfNatural; 4364 break; 4365 } 4366 } 4367 PetscFunctionReturn(PETSC_SUCCESS); 4368 } 4369 4370 /*@ 4371 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4372 4373 Not Collective 4374 4375 Input Parameter: 4376 . dm - The `DMPLEX` 4377 4378 Level: beginner 4379 4380 Note: 4381 This should be called after all calls to `DMPlexSetCone()` 4382 4383 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4384 @*/ 4385 PetscErrorCode DMPlexSymmetrize(DM dm) 4386 { 4387 DM_Plex *mesh = (DM_Plex *)dm->data; 4388 PetscInt *offsets; 4389 PetscInt supportSize; 4390 PetscInt pStart, pEnd, p; 4391 4392 PetscFunctionBegin; 4393 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4394 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4395 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4396 /* Calculate support sizes */ 4397 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4398 for (p = pStart; p < pEnd; ++p) { 4399 PetscInt dof, off, c; 4400 4401 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4402 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4403 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4404 } 4405 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4406 /* Calculate supports */ 4407 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4408 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4409 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4410 for (p = pStart; p < pEnd; ++p) { 4411 PetscInt dof, off, c; 4412 4413 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4414 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4415 for (c = off; c < off + dof; ++c) { 4416 const PetscInt q = mesh->cones[c]; 4417 PetscInt offS; 4418 4419 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4420 4421 mesh->supports[offS + offsets[q]] = p; 4422 ++offsets[q]; 4423 } 4424 } 4425 PetscCall(PetscFree(offsets)); 4426 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4427 PetscFunctionReturn(PETSC_SUCCESS); 4428 } 4429 4430 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4431 { 4432 IS stratumIS; 4433 4434 PetscFunctionBegin; 4435 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4436 if (PetscDefined(USE_DEBUG)) { 4437 PetscInt qStart, qEnd, numLevels, level; 4438 PetscBool overlap = PETSC_FALSE; 4439 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4440 for (level = 0; level < numLevels; level++) { 4441 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4442 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4443 overlap = PETSC_TRUE; 4444 break; 4445 } 4446 } 4447 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); 4448 } 4449 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4450 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4451 PetscCall(ISDestroy(&stratumIS)); 4452 PetscFunctionReturn(PETSC_SUCCESS); 4453 } 4454 4455 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4456 { 4457 PetscInt *pMin, *pMax; 4458 PetscInt pStart, pEnd; 4459 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4460 4461 PetscFunctionBegin; 4462 { 4463 DMLabel label2; 4464 4465 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4466 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4467 } 4468 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4469 for (PetscInt p = pStart; p < pEnd; ++p) { 4470 DMPolytopeType ct; 4471 4472 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4473 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4474 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4475 } 4476 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4477 for (PetscInt d = dmin; d <= dmax; ++d) { 4478 pMin[d] = PETSC_INT_MAX; 4479 pMax[d] = PETSC_INT_MIN; 4480 } 4481 for (PetscInt p = pStart; p < pEnd; ++p) { 4482 DMPolytopeType ct; 4483 PetscInt d; 4484 4485 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4486 d = DMPolytopeTypeGetDim(ct); 4487 pMin[d] = PetscMin(p, pMin[d]); 4488 pMax[d] = PetscMax(p, pMax[d]); 4489 } 4490 for (PetscInt d = dmin; d <= dmax; ++d) { 4491 if (pMin[d] > pMax[d]) continue; 4492 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4493 } 4494 PetscCall(PetscFree2(pMin, pMax)); 4495 PetscFunctionReturn(PETSC_SUCCESS); 4496 } 4497 4498 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4499 { 4500 PetscInt pStart, pEnd; 4501 PetscInt numRoots = 0, numLeaves = 0; 4502 4503 PetscFunctionBegin; 4504 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4505 { 4506 /* Initialize roots and count leaves */ 4507 PetscInt sMin = PETSC_INT_MAX; 4508 PetscInt sMax = PETSC_INT_MIN; 4509 PetscInt coneSize, supportSize; 4510 4511 for (PetscInt p = pStart; p < pEnd; ++p) { 4512 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4513 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4514 if (!coneSize && supportSize) { 4515 sMin = PetscMin(p, sMin); 4516 sMax = PetscMax(p, sMax); 4517 ++numRoots; 4518 } else if (!supportSize && coneSize) { 4519 ++numLeaves; 4520 } else if (!supportSize && !coneSize) { 4521 /* Isolated points */ 4522 sMin = PetscMin(p, sMin); 4523 sMax = PetscMax(p, sMax); 4524 } 4525 } 4526 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4527 } 4528 4529 if (numRoots + numLeaves == (pEnd - pStart)) { 4530 PetscInt sMin = PETSC_INT_MAX; 4531 PetscInt sMax = PETSC_INT_MIN; 4532 PetscInt coneSize, supportSize; 4533 4534 for (PetscInt p = pStart; p < pEnd; ++p) { 4535 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4536 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4537 if (!supportSize && coneSize) { 4538 sMin = PetscMin(p, sMin); 4539 sMax = PetscMax(p, sMax); 4540 } 4541 } 4542 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4543 } else { 4544 PetscInt level = 0; 4545 PetscInt qStart, qEnd; 4546 4547 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4548 while (qEnd > qStart) { 4549 PetscInt sMin = PETSC_INT_MAX; 4550 PetscInt sMax = PETSC_INT_MIN; 4551 4552 for (PetscInt q = qStart; q < qEnd; ++q) { 4553 const PetscInt *support; 4554 PetscInt supportSize; 4555 4556 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4557 PetscCall(DMPlexGetSupport(dm, q, &support)); 4558 for (PetscInt s = 0; s < supportSize; ++s) { 4559 sMin = PetscMin(support[s], sMin); 4560 sMax = PetscMax(support[s], sMax); 4561 } 4562 } 4563 PetscCall(DMLabelGetNumValues(label, &level)); 4564 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4565 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4566 } 4567 } 4568 PetscFunctionReturn(PETSC_SUCCESS); 4569 } 4570 4571 /*@ 4572 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4573 4574 Collective 4575 4576 Input Parameter: 4577 . dm - The `DMPLEX` 4578 4579 Level: beginner 4580 4581 Notes: 4582 The strata group all points of the same grade, and this function calculates the strata. This 4583 grade can be seen as the height (or depth) of the point in the DAG. 4584 4585 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4586 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4587 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4588 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4589 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4590 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4591 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4592 4593 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4594 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4595 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 4596 to interpolate only that one (e0), so that 4597 .vb 4598 cone(c0) = {e0, v2} 4599 cone(e0) = {v0, v1} 4600 .ve 4601 If `DMPlexStratify()` is run on this mesh, it will give depths 4602 .vb 4603 depth 0 = {v0, v1, v2} 4604 depth 1 = {e0, c0} 4605 .ve 4606 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4607 4608 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4609 4610 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4611 @*/ 4612 PetscErrorCode DMPlexStratify(DM dm) 4613 { 4614 DM_Plex *mesh = (DM_Plex *)dm->data; 4615 DMLabel label; 4616 PetscBool flg = PETSC_FALSE; 4617 4618 PetscFunctionBegin; 4619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4620 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4621 4622 // Create depth label 4623 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4624 PetscCall(DMCreateLabel(dm, "depth")); 4625 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4626 4627 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4628 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4629 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4630 4631 { /* just in case there is an empty process */ 4632 PetscInt numValues, maxValues = 0, v; 4633 4634 PetscCall(DMLabelGetNumValues(label, &numValues)); 4635 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4636 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4637 } 4638 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4639 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4640 PetscFunctionReturn(PETSC_SUCCESS); 4641 } 4642 4643 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4644 { 4645 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4646 PetscInt dim, depth, pheight, coneSize; 4647 PetscBool preferTensor; 4648 4649 PetscFunctionBeginHot; 4650 PetscCall(DMGetDimension(dm, &dim)); 4651 PetscCall(DMPlexGetDepth(dm, &depth)); 4652 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4653 PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor)); 4654 pheight = depth - pdepth; 4655 if (depth <= 1) { 4656 switch (pdepth) { 4657 case 0: 4658 ct = DM_POLYTOPE_POINT; 4659 break; 4660 case 1: 4661 switch (coneSize) { 4662 case 2: 4663 ct = DM_POLYTOPE_SEGMENT; 4664 break; 4665 case 3: 4666 ct = DM_POLYTOPE_TRIANGLE; 4667 break; 4668 case 4: 4669 switch (dim) { 4670 case 2: 4671 ct = DM_POLYTOPE_QUADRILATERAL; 4672 break; 4673 case 3: 4674 ct = DM_POLYTOPE_TETRAHEDRON; 4675 break; 4676 default: 4677 break; 4678 } 4679 break; 4680 case 5: 4681 ct = DM_POLYTOPE_PYRAMID; 4682 break; 4683 case 6: 4684 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4685 break; 4686 case 8: 4687 ct = DM_POLYTOPE_HEXAHEDRON; 4688 break; 4689 default: 4690 break; 4691 } 4692 } 4693 } else { 4694 if (pdepth == 0) { 4695 ct = DM_POLYTOPE_POINT; 4696 } else if (pheight == 0) { 4697 switch (dim) { 4698 case 1: 4699 switch (coneSize) { 4700 case 2: 4701 ct = DM_POLYTOPE_SEGMENT; 4702 break; 4703 default: 4704 break; 4705 } 4706 break; 4707 case 2: 4708 switch (coneSize) { 4709 case 3: 4710 ct = DM_POLYTOPE_TRIANGLE; 4711 break; 4712 case 4: 4713 ct = DM_POLYTOPE_QUADRILATERAL; 4714 break; 4715 default: 4716 break; 4717 } 4718 break; 4719 case 3: 4720 switch (coneSize) { 4721 case 4: 4722 ct = DM_POLYTOPE_TETRAHEDRON; 4723 break; 4724 case 5: { 4725 const PetscInt *cone; 4726 PetscInt faceConeSize; 4727 4728 PetscCall(DMPlexGetCone(dm, p, &cone)); 4729 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4730 switch (faceConeSize) { 4731 case 3: 4732 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4733 break; 4734 case 4: 4735 ct = DM_POLYTOPE_PYRAMID; 4736 break; 4737 } 4738 } break; 4739 case 6: 4740 ct = DM_POLYTOPE_HEXAHEDRON; 4741 break; 4742 default: 4743 break; 4744 } 4745 break; 4746 default: 4747 break; 4748 } 4749 } else if (pheight > 0) { 4750 switch (coneSize) { 4751 case 2: 4752 ct = DM_POLYTOPE_SEGMENT; 4753 break; 4754 case 3: 4755 ct = DM_POLYTOPE_TRIANGLE; 4756 break; 4757 case 4: 4758 ct = DM_POLYTOPE_QUADRILATERAL; 4759 break; 4760 default: 4761 break; 4762 } 4763 } 4764 } 4765 *pt = ct; 4766 PetscFunctionReturn(PETSC_SUCCESS); 4767 } 4768 4769 /*@ 4770 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4771 4772 Collective 4773 4774 Input Parameter: 4775 . dm - The `DMPLEX` 4776 4777 Level: developer 4778 4779 Note: 4780 This function is normally called automatically when a cell type is requested. It creates an 4781 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4782 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4783 4784 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4785 4786 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4787 @*/ 4788 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4789 { 4790 DM_Plex *mesh; 4791 DMLabel ctLabel; 4792 PetscInt pStart, pEnd, p; 4793 4794 PetscFunctionBegin; 4795 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4796 mesh = (DM_Plex *)dm->data; 4797 PetscCall(DMCreateLabel(dm, "celltype")); 4798 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4799 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4800 PetscCall(PetscFree(mesh->cellTypes)); 4801 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4802 for (p = pStart; p < pEnd; ++p) { 4803 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4804 PetscInt pdepth; 4805 4806 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4807 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4808 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]); 4809 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4810 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4811 } 4812 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4813 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4814 PetscFunctionReturn(PETSC_SUCCESS); 4815 } 4816 4817 /*@C 4818 DMPlexGetJoin - Get an array for the join of the set of points 4819 4820 Not Collective 4821 4822 Input Parameters: 4823 + dm - The `DMPLEX` object 4824 . numPoints - The number of input points for the join 4825 - points - The input points 4826 4827 Output Parameters: 4828 + numCoveredPoints - The number of points in the join 4829 - coveredPoints - The points in the join 4830 4831 Level: intermediate 4832 4833 Note: 4834 Currently, this is restricted to a single level join 4835 4836 Fortran Notes: 4837 `converedPoints` must be declared with 4838 .vb 4839 PetscInt, pointer :: coveredPints(:) 4840 .ve 4841 4842 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4843 @*/ 4844 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4845 { 4846 DM_Plex *mesh = (DM_Plex *)dm->data; 4847 PetscInt *join[2]; 4848 PetscInt joinSize, i = 0; 4849 PetscInt dof, off, p, c, m; 4850 PetscInt maxSupportSize; 4851 4852 PetscFunctionBegin; 4853 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4854 PetscAssertPointer(points, 3); 4855 PetscAssertPointer(numCoveredPoints, 4); 4856 PetscAssertPointer(coveredPoints, 5); 4857 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4858 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4859 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4860 /* Copy in support of first point */ 4861 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4862 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4863 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4864 /* Check each successive support */ 4865 for (p = 1; p < numPoints; ++p) { 4866 PetscInt newJoinSize = 0; 4867 4868 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4869 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4870 for (c = 0; c < dof; ++c) { 4871 const PetscInt point = mesh->supports[off + c]; 4872 4873 for (m = 0; m < joinSize; ++m) { 4874 if (point == join[i][m]) { 4875 join[1 - i][newJoinSize++] = point; 4876 break; 4877 } 4878 } 4879 } 4880 joinSize = newJoinSize; 4881 i = 1 - i; 4882 } 4883 *numCoveredPoints = joinSize; 4884 *coveredPoints = join[i]; 4885 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4886 PetscFunctionReturn(PETSC_SUCCESS); 4887 } 4888 4889 /*@C 4890 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4891 4892 Not Collective 4893 4894 Input Parameters: 4895 + dm - The `DMPLEX` object 4896 . numPoints - The number of input points for the join 4897 - points - The input points 4898 4899 Output Parameters: 4900 + numCoveredPoints - The number of points in the join 4901 - coveredPoints - The points in the join 4902 4903 Level: intermediate 4904 4905 Fortran Notes: 4906 `converedPoints` must be declared with 4907 .vb 4908 PetscInt, pointer :: coveredPoints(:) 4909 .ve 4910 4911 Pass `PETSC_NULL_INTEGER` for `numCoveredPoints` if it is not needed 4912 4913 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4914 @*/ 4915 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4916 { 4917 PetscFunctionBegin; 4918 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4919 if (points) PetscAssertPointer(points, 3); 4920 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4921 PetscAssertPointer(coveredPoints, 5); 4922 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4923 if (numCoveredPoints) *numCoveredPoints = 0; 4924 PetscFunctionReturn(PETSC_SUCCESS); 4925 } 4926 4927 /*@C 4928 DMPlexGetFullJoin - Get an array for the join of the set of points 4929 4930 Not Collective 4931 4932 Input Parameters: 4933 + dm - The `DMPLEX` object 4934 . numPoints - The number of input points for the join 4935 - points - The input points, its length is `numPoints` 4936 4937 Output Parameters: 4938 + numCoveredPoints - The number of points in the join 4939 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4940 4941 Level: intermediate 4942 4943 Fortran Notes: 4944 .vb 4945 PetscInt, pointer :: coveredPints(:) 4946 .ve 4947 4948 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4949 @*/ 4950 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4951 { 4952 PetscInt *offsets, **closures; 4953 PetscInt *join[2]; 4954 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4955 PetscInt p, d, c, m, ms; 4956 4957 PetscFunctionBegin; 4958 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4959 PetscAssertPointer(points, 3); 4960 PetscAssertPointer(numCoveredPoints, 4); 4961 PetscAssertPointer(coveredPoints, 5); 4962 4963 PetscCall(DMPlexGetDepth(dm, &depth)); 4964 PetscCall(PetscCalloc1(numPoints, &closures)); 4965 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4966 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4967 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4968 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4969 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4970 4971 for (p = 0; p < numPoints; ++p) { 4972 PetscInt closureSize; 4973 4974 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4975 4976 offsets[p * (depth + 2) + 0] = 0; 4977 for (d = 0; d < depth + 1; ++d) { 4978 PetscInt pStart, pEnd, i; 4979 4980 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4981 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4982 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4983 offsets[p * (depth + 2) + d + 1] = i; 4984 break; 4985 } 4986 } 4987 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4988 } 4989 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); 4990 } 4991 for (d = 0; d < depth + 1; ++d) { 4992 PetscInt dof; 4993 4994 /* Copy in support of first point */ 4995 dof = offsets[d + 1] - offsets[d]; 4996 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4997 /* Check each successive cone */ 4998 for (p = 1; p < numPoints && joinSize; ++p) { 4999 PetscInt newJoinSize = 0; 5000 5001 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 5002 for (c = 0; c < dof; ++c) { 5003 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 5004 5005 for (m = 0; m < joinSize; ++m) { 5006 if (point == join[i][m]) { 5007 join[1 - i][newJoinSize++] = point; 5008 break; 5009 } 5010 } 5011 } 5012 joinSize = newJoinSize; 5013 i = 1 - i; 5014 } 5015 if (joinSize) break; 5016 } 5017 *numCoveredPoints = joinSize; 5018 *coveredPoints = join[i]; 5019 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 5020 PetscCall(PetscFree(closures)); 5021 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 5022 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 5023 PetscFunctionReturn(PETSC_SUCCESS); 5024 } 5025 5026 /*@C 5027 DMPlexGetMeet - Get an array for the meet of the set of points 5028 5029 Not Collective 5030 5031 Input Parameters: 5032 + dm - The `DMPLEX` object 5033 . numPoints - The number of input points for the meet 5034 - points - The input points, of length `numPoints` 5035 5036 Output Parameters: 5037 + numCoveringPoints - The number of points in the meet 5038 - coveringPoints - The points in the meet, of length `numCoveringPoints` 5039 5040 Level: intermediate 5041 5042 Note: 5043 Currently, this is restricted to a single level meet 5044 5045 Fortran Note: 5046 `coveringPoints` must be declared with 5047 .vb 5048 PetscInt, pointer :: coveringPoints(:) 5049 .ve 5050 5051 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5052 @*/ 5053 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 5054 { 5055 DM_Plex *mesh = (DM_Plex *)dm->data; 5056 PetscInt *meet[2]; 5057 PetscInt meetSize, i = 0; 5058 PetscInt dof, off, p, c, m; 5059 PetscInt maxConeSize; 5060 5061 PetscFunctionBegin; 5062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5063 PetscAssertPointer(points, 3); 5064 PetscAssertPointer(numCoveringPoints, 4); 5065 PetscAssertPointer(coveringPoints, 5); 5066 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 5067 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 5068 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 5069 /* Copy in cone of first point */ 5070 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 5071 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 5072 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5073 /* Check each successive cone */ 5074 for (p = 1; p < numPoints; ++p) { 5075 PetscInt newMeetSize = 0; 5076 5077 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5078 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5079 for (c = 0; c < dof; ++c) { 5080 const PetscInt point = mesh->cones[off + c]; 5081 5082 for (m = 0; m < meetSize; ++m) { 5083 if (point == meet[i][m]) { 5084 meet[1 - i][newMeetSize++] = point; 5085 break; 5086 } 5087 } 5088 } 5089 meetSize = newMeetSize; 5090 i = 1 - i; 5091 } 5092 *numCoveringPoints = meetSize; 5093 *coveringPoints = meet[i]; 5094 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5095 PetscFunctionReturn(PETSC_SUCCESS); 5096 } 5097 5098 /*@C 5099 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5100 5101 Not Collective 5102 5103 Input Parameters: 5104 + dm - The `DMPLEX` object 5105 . numPoints - The number of input points for the meet 5106 - points - The input points 5107 5108 Output Parameters: 5109 + numCoveredPoints - The number of points in the meet 5110 - coveredPoints - The points in the meet 5111 5112 Level: intermediate 5113 5114 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5115 @*/ 5116 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5117 { 5118 PetscFunctionBegin; 5119 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5120 if (points) PetscAssertPointer(points, 3); 5121 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5122 PetscAssertPointer(coveredPoints, 5); 5123 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5124 if (numCoveredPoints) *numCoveredPoints = 0; 5125 PetscFunctionReturn(PETSC_SUCCESS); 5126 } 5127 5128 /*@C 5129 DMPlexGetFullMeet - Get an array for the meet of the set of points 5130 5131 Not Collective 5132 5133 Input Parameters: 5134 + dm - The `DMPLEX` object 5135 . numPoints - The number of input points for the meet 5136 - points - The input points, of length `numPoints` 5137 5138 Output Parameters: 5139 + numCoveredPoints - The number of points in the meet 5140 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5141 5142 Level: intermediate 5143 5144 Fortran Notes: 5145 `coveredPoints` must be declared with 5146 .vb 5147 PetscInt, pointer :: coveredPoints(:) 5148 .ve 5149 5150 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5151 @*/ 5152 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5153 { 5154 PetscInt *offsets, **closures; 5155 PetscInt *meet[2]; 5156 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5157 PetscInt p, h, c, m, mc; 5158 5159 PetscFunctionBegin; 5160 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5161 PetscAssertPointer(points, 3); 5162 PetscAssertPointer(numCoveredPoints, 4); 5163 PetscAssertPointer(coveredPoints, 5); 5164 5165 PetscCall(DMPlexGetDepth(dm, &height)); 5166 PetscCall(PetscMalloc1(numPoints, &closures)); 5167 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5168 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5169 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5170 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5171 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5172 5173 for (p = 0; p < numPoints; ++p) { 5174 PetscInt closureSize; 5175 5176 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5177 5178 offsets[p * (height + 2) + 0] = 0; 5179 for (h = 0; h < height + 1; ++h) { 5180 PetscInt pStart, pEnd, i; 5181 5182 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5183 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5184 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5185 offsets[p * (height + 2) + h + 1] = i; 5186 break; 5187 } 5188 } 5189 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5190 } 5191 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); 5192 } 5193 for (h = 0; h < height + 1; ++h) { 5194 PetscInt dof; 5195 5196 /* Copy in cone of first point */ 5197 dof = offsets[h + 1] - offsets[h]; 5198 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5199 /* Check each successive cone */ 5200 for (p = 1; p < numPoints && meetSize; ++p) { 5201 PetscInt newMeetSize = 0; 5202 5203 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5204 for (c = 0; c < dof; ++c) { 5205 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5206 5207 for (m = 0; m < meetSize; ++m) { 5208 if (point == meet[i][m]) { 5209 meet[1 - i][newMeetSize++] = point; 5210 break; 5211 } 5212 } 5213 } 5214 meetSize = newMeetSize; 5215 i = 1 - i; 5216 } 5217 if (meetSize) break; 5218 } 5219 *numCoveredPoints = meetSize; 5220 *coveredPoints = meet[i]; 5221 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5222 PetscCall(PetscFree(closures)); 5223 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5224 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5225 PetscFunctionReturn(PETSC_SUCCESS); 5226 } 5227 5228 /*@ 5229 DMPlexEqual - Determine if two `DM` have the same topology 5230 5231 Not Collective 5232 5233 Input Parameters: 5234 + dmA - A `DMPLEX` object 5235 - dmB - A `DMPLEX` object 5236 5237 Output Parameter: 5238 . equal - `PETSC_TRUE` if the topologies are identical 5239 5240 Level: intermediate 5241 5242 Note: 5243 We are not solving graph isomorphism, so we do not permute. 5244 5245 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5246 @*/ 5247 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5248 { 5249 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5250 5251 PetscFunctionBegin; 5252 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5253 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5254 PetscAssertPointer(equal, 3); 5255 5256 *equal = PETSC_FALSE; 5257 PetscCall(DMPlexGetDepth(dmA, &depth)); 5258 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5259 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5260 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5261 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5262 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5263 for (p = pStart; p < pEnd; ++p) { 5264 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5265 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5266 5267 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5268 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5269 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5270 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5271 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5272 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5273 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5274 for (c = 0; c < coneSize; ++c) { 5275 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5276 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5277 } 5278 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5279 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5280 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5281 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5282 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5283 for (s = 0; s < supportSize; ++s) { 5284 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5285 } 5286 } 5287 *equal = PETSC_TRUE; 5288 PetscFunctionReturn(PETSC_SUCCESS); 5289 } 5290 5291 /*@ 5292 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5293 5294 Not Collective 5295 5296 Input Parameters: 5297 + dm - The `DMPLEX` 5298 . cellDim - The cell dimension 5299 - numCorners - The number of vertices on a cell 5300 5301 Output Parameter: 5302 . numFaceVertices - The number of vertices on a face 5303 5304 Level: developer 5305 5306 Note: 5307 Of course this can only work for a restricted set of symmetric shapes 5308 5309 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5310 @*/ 5311 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5312 { 5313 MPI_Comm comm; 5314 5315 PetscFunctionBegin; 5316 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5317 PetscAssertPointer(numFaceVertices, 4); 5318 switch (cellDim) { 5319 case 0: 5320 *numFaceVertices = 0; 5321 break; 5322 case 1: 5323 *numFaceVertices = 1; 5324 break; 5325 case 2: 5326 switch (numCorners) { 5327 case 3: /* triangle */ 5328 *numFaceVertices = 2; /* Edge has 2 vertices */ 5329 break; 5330 case 4: /* quadrilateral */ 5331 *numFaceVertices = 2; /* Edge has 2 vertices */ 5332 break; 5333 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5334 *numFaceVertices = 3; /* Edge has 3 vertices */ 5335 break; 5336 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5337 *numFaceVertices = 3; /* Edge has 3 vertices */ 5338 break; 5339 default: 5340 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5341 } 5342 break; 5343 case 3: 5344 switch (numCorners) { 5345 case 4: /* tetradehdron */ 5346 *numFaceVertices = 3; /* Face has 3 vertices */ 5347 break; 5348 case 6: /* tet cohesive cells */ 5349 *numFaceVertices = 4; /* Face has 4 vertices */ 5350 break; 5351 case 8: /* hexahedron */ 5352 *numFaceVertices = 4; /* Face has 4 vertices */ 5353 break; 5354 case 9: /* tet cohesive Lagrange cells */ 5355 *numFaceVertices = 6; /* Face has 6 vertices */ 5356 break; 5357 case 10: /* quadratic tetrahedron */ 5358 *numFaceVertices = 6; /* Face has 6 vertices */ 5359 break; 5360 case 12: /* hex cohesive Lagrange cells */ 5361 *numFaceVertices = 6; /* Face has 6 vertices */ 5362 break; 5363 case 18: /* quadratic tet cohesive Lagrange cells */ 5364 *numFaceVertices = 6; /* Face has 6 vertices */ 5365 break; 5366 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5367 *numFaceVertices = 9; /* Face has 9 vertices */ 5368 break; 5369 default: 5370 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5371 } 5372 break; 5373 default: 5374 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5375 } 5376 PetscFunctionReturn(PETSC_SUCCESS); 5377 } 5378 5379 /*@ 5380 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5381 5382 Not Collective 5383 5384 Input Parameter: 5385 . dm - The `DMPLEX` object 5386 5387 Output Parameter: 5388 . depthLabel - The `DMLabel` recording point depth 5389 5390 Level: developer 5391 5392 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5393 @*/ 5394 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5395 { 5396 PetscFunctionBegin; 5397 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5398 PetscAssertPointer(depthLabel, 2); 5399 *depthLabel = dm->depthLabel; 5400 PetscFunctionReturn(PETSC_SUCCESS); 5401 } 5402 5403 /*@ 5404 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5405 5406 Not Collective 5407 5408 Input Parameter: 5409 . dm - The `DMPLEX` object 5410 5411 Output Parameter: 5412 . depth - The number of strata (breadth first levels) in the DAG 5413 5414 Level: developer 5415 5416 Notes: 5417 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5418 5419 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5420 5421 An empty mesh gives -1. 5422 5423 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5424 @*/ 5425 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5426 { 5427 DM_Plex *mesh = (DM_Plex *)dm->data; 5428 DMLabel label; 5429 PetscInt d = -1; 5430 5431 PetscFunctionBegin; 5432 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5433 PetscAssertPointer(depth, 2); 5434 if (mesh->tr) { 5435 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5436 } else { 5437 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5438 // Allow missing depths 5439 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5440 *depth = d; 5441 } 5442 PetscFunctionReturn(PETSC_SUCCESS); 5443 } 5444 5445 /*@ 5446 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5447 5448 Not Collective 5449 5450 Input Parameters: 5451 + dm - The `DMPLEX` object 5452 - depth - The requested depth 5453 5454 Output Parameters: 5455 + start - The first point at this `depth` 5456 - end - One beyond the last point at this `depth` 5457 5458 Level: developer 5459 5460 Notes: 5461 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5462 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5463 higher dimension, e.g., "edges". 5464 5465 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5466 @*/ 5467 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PeOp PetscInt *start, PeOp PetscInt *end) 5468 { 5469 DM_Plex *mesh = (DM_Plex *)dm->data; 5470 DMLabel label; 5471 PetscInt pStart, pEnd; 5472 5473 PetscFunctionBegin; 5474 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5475 if (start) { 5476 PetscAssertPointer(start, 3); 5477 *start = 0; 5478 } 5479 if (end) { 5480 PetscAssertPointer(end, 4); 5481 *end = 0; 5482 } 5483 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5484 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5485 if (depth < 0) { 5486 if (start) *start = pStart; 5487 if (end) *end = pEnd; 5488 PetscFunctionReturn(PETSC_SUCCESS); 5489 } 5490 if (mesh->tr) { 5491 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5492 } else { 5493 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5494 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5495 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5496 } 5497 PetscFunctionReturn(PETSC_SUCCESS); 5498 } 5499 5500 /*@ 5501 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5502 5503 Not Collective 5504 5505 Input Parameters: 5506 + dm - The `DMPLEX` object 5507 - height - The requested height 5508 5509 Output Parameters: 5510 + start - The first point at this `height` 5511 - end - One beyond the last point at this `height` 5512 5513 Level: developer 5514 5515 Notes: 5516 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5517 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5518 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5519 5520 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5521 @*/ 5522 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PeOp PetscInt *start, PeOp PetscInt *end) 5523 { 5524 DMLabel label; 5525 PetscInt depth, pStart, pEnd; 5526 5527 PetscFunctionBegin; 5528 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5529 if (start) { 5530 PetscAssertPointer(start, 3); 5531 *start = 0; 5532 } 5533 if (end) { 5534 PetscAssertPointer(end, 4); 5535 *end = 0; 5536 } 5537 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5538 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5539 if (height < 0) { 5540 if (start) *start = pStart; 5541 if (end) *end = pEnd; 5542 PetscFunctionReturn(PETSC_SUCCESS); 5543 } 5544 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5545 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5546 else PetscCall(DMGetDimension(dm, &depth)); 5547 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5548 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5549 PetscFunctionReturn(PETSC_SUCCESS); 5550 } 5551 5552 /*@ 5553 DMPlexGetPointDepth - Get the `depth` of a given point 5554 5555 Not Collective 5556 5557 Input Parameters: 5558 + dm - The `DMPLEX` object 5559 - point - The point 5560 5561 Output Parameter: 5562 . depth - The depth of the `point` 5563 5564 Level: intermediate 5565 5566 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5567 @*/ 5568 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5569 { 5570 PetscFunctionBegin; 5571 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5572 PetscAssertPointer(depth, 3); 5573 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5574 PetscFunctionReturn(PETSC_SUCCESS); 5575 } 5576 5577 /*@ 5578 DMPlexGetPointHeight - Get the `height` of a given point 5579 5580 Not Collective 5581 5582 Input Parameters: 5583 + dm - The `DMPLEX` object 5584 - point - The point 5585 5586 Output Parameter: 5587 . height - The height of the `point` 5588 5589 Level: intermediate 5590 5591 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5592 @*/ 5593 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5594 { 5595 PetscInt n, pDepth; 5596 5597 PetscFunctionBegin; 5598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5599 PetscAssertPointer(height, 3); 5600 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5601 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5602 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5603 PetscFunctionReturn(PETSC_SUCCESS); 5604 } 5605 5606 /*@ 5607 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5608 5609 Not Collective 5610 5611 Input Parameter: 5612 . dm - The `DMPLEX` object 5613 5614 Output Parameter: 5615 . celltypeLabel - The `DMLabel` recording cell polytope type 5616 5617 Level: developer 5618 5619 Note: 5620 This function will trigger automatica computation of cell types. This can be disabled by calling 5621 `DMCreateLabel`(dm, "celltype") beforehand. 5622 5623 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5624 @*/ 5625 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5626 { 5627 PetscFunctionBegin; 5628 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5629 PetscAssertPointer(celltypeLabel, 2); 5630 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5631 *celltypeLabel = dm->celltypeLabel; 5632 PetscFunctionReturn(PETSC_SUCCESS); 5633 } 5634 5635 /*@ 5636 DMPlexGetCellType - Get the polytope type of a given cell 5637 5638 Not Collective 5639 5640 Input Parameters: 5641 + dm - The `DMPLEX` object 5642 - cell - The cell 5643 5644 Output Parameter: 5645 . celltype - The polytope type of the cell 5646 5647 Level: intermediate 5648 5649 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5650 @*/ 5651 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5652 { 5653 DM_Plex *mesh = (DM_Plex *)dm->data; 5654 DMLabel label; 5655 PetscInt ct; 5656 5657 PetscFunctionBegin; 5658 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5659 PetscAssertPointer(celltype, 3); 5660 if (mesh->tr) { 5661 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5662 } else { 5663 PetscInt pStart, pEnd; 5664 5665 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5666 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5667 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5668 if (pEnd <= pStart) { 5669 *celltype = DM_POLYTOPE_UNKNOWN; 5670 PetscFunctionReturn(PETSC_SUCCESS); 5671 } 5672 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5673 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5674 for (PetscInt p = pStart; p < pEnd; p++) { 5675 PetscCall(DMLabelGetValue(label, p, &ct)); 5676 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5677 } 5678 } 5679 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5680 if (PetscDefined(USE_DEBUG)) { 5681 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5682 PetscCall(DMLabelGetValue(label, cell, &ct)); 5683 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5684 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5685 } 5686 } 5687 PetscFunctionReturn(PETSC_SUCCESS); 5688 } 5689 5690 /*@ 5691 DMPlexSetCellType - Set the polytope type of a given cell 5692 5693 Not Collective 5694 5695 Input Parameters: 5696 + dm - The `DMPLEX` object 5697 . cell - The cell 5698 - celltype - The polytope type of the cell 5699 5700 Level: advanced 5701 5702 Note: 5703 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5704 is executed. This function will override the computed type. However, if automatic classification will not succeed 5705 and a user wants to manually specify all types, the classification must be disabled by calling 5706 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5707 5708 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5709 @*/ 5710 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5711 { 5712 DM_Plex *mesh = (DM_Plex *)dm->data; 5713 DMLabel label; 5714 PetscInt pStart, pEnd; 5715 5716 PetscFunctionBegin; 5717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5718 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5719 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5720 PetscCall(DMLabelSetValue(label, cell, celltype)); 5721 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5722 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5723 PetscFunctionReturn(PETSC_SUCCESS); 5724 } 5725 5726 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5727 { 5728 PetscSection section; 5729 PetscInt maxHeight; 5730 const char *prefix; 5731 5732 PetscFunctionBegin; 5733 PetscCall(DMClone(dm, cdm)); 5734 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5735 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5736 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5737 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5738 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5739 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5740 PetscCall(DMSetLocalSection(*cdm, section)); 5741 PetscCall(PetscSectionDestroy(§ion)); 5742 5743 PetscCall(DMSetNumFields(*cdm, 1)); 5744 PetscCall(DMCreateDS(*cdm)); 5745 (*cdm)->cloneOpts = PETSC_TRUE; 5746 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5747 PetscFunctionReturn(PETSC_SUCCESS); 5748 } 5749 5750 PetscErrorCode DMCreateCellCoordinateDM_Plex(DM dm, DM *cdm) 5751 { 5752 DM cgcdm; 5753 PetscSection section; 5754 const char *prefix; 5755 5756 PetscFunctionBegin; 5757 PetscCall(DMGetCoordinateDM(dm, &cgcdm)); 5758 PetscCall(DMClone(cgcdm, cdm)); 5759 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5760 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5761 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cellcdm_")); 5762 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5763 PetscCall(DMSetLocalSection(*cdm, section)); 5764 PetscCall(PetscSectionDestroy(§ion)); 5765 PetscCall(DMSetNumFields(*cdm, 1)); 5766 PetscCall(DMCreateDS(*cdm)); 5767 (*cdm)->cloneOpts = PETSC_TRUE; 5768 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5769 PetscFunctionReturn(PETSC_SUCCESS); 5770 } 5771 5772 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5773 { 5774 Vec coordsLocal, cellCoordsLocal; 5775 DM coordsDM, cellCoordsDM; 5776 5777 PetscFunctionBegin; 5778 *field = NULL; 5779 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5780 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5781 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5782 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5783 if (coordsLocal && coordsDM) { 5784 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5785 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5786 } 5787 PetscFunctionReturn(PETSC_SUCCESS); 5788 } 5789 5790 /*@ 5791 DMPlexGetConeSection - Return a section which describes the layout of cone data 5792 5793 Not Collective 5794 5795 Input Parameter: 5796 . dm - The `DMPLEX` object 5797 5798 Output Parameter: 5799 . section - The `PetscSection` object 5800 5801 Level: developer 5802 5803 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5804 @*/ 5805 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5806 { 5807 DM_Plex *mesh = (DM_Plex *)dm->data; 5808 5809 PetscFunctionBegin; 5810 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5811 if (section) *section = mesh->coneSection; 5812 PetscFunctionReturn(PETSC_SUCCESS); 5813 } 5814 5815 /*@ 5816 DMPlexGetSupportSection - Return a section which describes the layout of support data 5817 5818 Not Collective 5819 5820 Input Parameter: 5821 . dm - The `DMPLEX` object 5822 5823 Output Parameter: 5824 . section - The `PetscSection` object 5825 5826 Level: developer 5827 5828 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5829 @*/ 5830 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5831 { 5832 DM_Plex *mesh = (DM_Plex *)dm->data; 5833 5834 PetscFunctionBegin; 5835 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5836 if (section) *section = mesh->supportSection; 5837 PetscFunctionReturn(PETSC_SUCCESS); 5838 } 5839 5840 /*@C 5841 DMPlexGetCones - Return cone data 5842 5843 Not Collective 5844 5845 Input Parameter: 5846 . dm - The `DMPLEX` object 5847 5848 Output Parameter: 5849 . cones - The cone for each point 5850 5851 Level: developer 5852 5853 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5854 @*/ 5855 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5856 { 5857 DM_Plex *mesh = (DM_Plex *)dm->data; 5858 5859 PetscFunctionBegin; 5860 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5861 if (cones) *cones = mesh->cones; 5862 PetscFunctionReturn(PETSC_SUCCESS); 5863 } 5864 5865 /*@C 5866 DMPlexGetConeOrientations - Return cone orientation data 5867 5868 Not Collective 5869 5870 Input Parameter: 5871 . dm - The `DMPLEX` object 5872 5873 Output Parameter: 5874 . coneOrientations - The array of cone orientations for all points 5875 5876 Level: developer 5877 5878 Notes: 5879 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5880 as returned by `DMPlexGetConeOrientation()`. 5881 5882 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5883 5884 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5885 @*/ 5886 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5887 { 5888 DM_Plex *mesh = (DM_Plex *)dm->data; 5889 5890 PetscFunctionBegin; 5891 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5892 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5893 PetscFunctionReturn(PETSC_SUCCESS); 5894 } 5895 5896 /* FEM Support */ 5897 5898 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5899 { 5900 PetscInt depth; 5901 5902 PetscFunctionBegin; 5903 PetscCall(DMPlexGetDepth(plex, &depth)); 5904 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5905 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5906 PetscFunctionReturn(PETSC_SUCCESS); 5907 } 5908 5909 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5910 { 5911 PetscInt depth; 5912 5913 PetscFunctionBegin; 5914 PetscCall(DMPlexGetDepth(plex, &depth)); 5915 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5916 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5917 PetscFunctionReturn(PETSC_SUCCESS); 5918 } 5919 5920 /* 5921 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5922 representing a line in the section. 5923 */ 5924 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5925 { 5926 PetscObject obj; 5927 PetscClassId id; 5928 PetscFE fe = NULL; 5929 5930 PetscFunctionBeginHot; 5931 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5932 PetscCall(DMGetField(dm, field, NULL, &obj)); 5933 PetscCall(PetscObjectGetClassId(obj, &id)); 5934 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5935 5936 if (!fe) { 5937 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5938 /* An order k SEM disc has k-1 dofs on an edge */ 5939 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5940 *k = *k / *Nc + 1; 5941 } else { 5942 PetscInt dual_space_size, dim; 5943 PetscDualSpace dsp; 5944 5945 PetscCall(DMGetDimension(dm, &dim)); 5946 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5947 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5948 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5949 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5950 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5951 } 5952 PetscFunctionReturn(PETSC_SUCCESS); 5953 } 5954 5955 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5956 { 5957 PetscFunctionBeginHot; 5958 if (tensor) { 5959 *dof = PetscPowInt(k + 1, dim); 5960 } else { 5961 switch (dim) { 5962 case 1: 5963 *dof = k + 1; 5964 break; 5965 case 2: 5966 *dof = ((k + 1) * (k + 2)) / 2; 5967 break; 5968 case 3: 5969 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5970 break; 5971 default: 5972 *dof = 0; 5973 } 5974 } 5975 PetscFunctionReturn(PETSC_SUCCESS); 5976 } 5977 5978 /*@ 5979 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5980 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5981 section provided (or the section of the `DM`). 5982 5983 Input Parameters: 5984 + dm - The `DM` 5985 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5986 - section - The `PetscSection` to reorder, or `NULL` for the default section 5987 5988 Example: 5989 A typical interpolated single-quad mesh might order points as 5990 .vb 5991 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5992 5993 v4 -- e6 -- v3 5994 | | 5995 e7 c0 e8 5996 | | 5997 v1 -- e5 -- v2 5998 .ve 5999 6000 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 6001 dofs in the order of points, e.g., 6002 .vb 6003 c0 -> [0,1,2,3] 6004 v1 -> [4] 6005 ... 6006 e5 -> [8, 9] 6007 .ve 6008 6009 which corresponds to the dofs 6010 .vb 6011 6 10 11 7 6012 13 2 3 15 6013 12 0 1 14 6014 4 8 9 5 6015 .ve 6016 6017 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 6018 .vb 6019 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 6020 .ve 6021 6022 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 6023 .vb 6024 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 6025 .ve 6026 6027 Level: developer 6028 6029 Notes: 6030 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 6031 degree of the basis. 6032 6033 This is required to run with libCEED. 6034 6035 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 6036 @*/ 6037 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 6038 { 6039 DMLabel label; 6040 PetscInt dim, depth = -1, eStart = -1, Nf; 6041 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 6042 6043 PetscFunctionBegin; 6044 PetscCall(DMGetDimension(dm, &dim)); 6045 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 6046 if (point < 0) { 6047 PetscInt sStart, sEnd; 6048 6049 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6050 point = sEnd - sStart ? sStart : point; 6051 } 6052 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6053 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6054 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6055 if (depth == 1) { 6056 eStart = point; 6057 } else if (depth == dim) { 6058 const PetscInt *cone; 6059 6060 PetscCall(DMPlexGetCone(dm, point, &cone)); 6061 if (dim == 2) eStart = cone[0]; 6062 else if (dim == 3) { 6063 const PetscInt *cone2; 6064 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6065 eStart = cone2[0]; 6066 } 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); 6067 } 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); 6068 6069 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6070 for (PetscInt d = 1; d <= dim; d++) { 6071 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6072 PetscInt *perm; 6073 6074 for (f = 0; f < Nf; ++f) { 6075 PetscInt dof; 6076 6077 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6078 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6079 if (!continuous && d < dim) continue; 6080 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6081 size += dof * Nc; 6082 } 6083 PetscCall(PetscMalloc1(size, &perm)); 6084 for (f = 0; f < Nf; ++f) { 6085 switch (d) { 6086 case 1: 6087 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6088 if (!continuous && d < dim) continue; 6089 /* 6090 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6091 We want [ vtx0; edge of length k-1; vtx1 ] 6092 */ 6093 if (continuous) { 6094 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6095 for (i = 0; i < k - 1; i++) 6096 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6097 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6098 foffset = offset; 6099 } else { 6100 PetscInt dof; 6101 6102 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6103 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6104 foffset = offset; 6105 } 6106 break; 6107 case 2: 6108 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6109 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6110 if (!continuous && d < dim) continue; 6111 /* The SEM order is 6112 6113 v_lb, {e_b}, v_rb, 6114 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6115 v_lt, reverse {e_t}, v_rt 6116 */ 6117 if (continuous) { 6118 const PetscInt of = 0; 6119 const PetscInt oeb = of + PetscSqr(k - 1); 6120 const PetscInt oer = oeb + (k - 1); 6121 const PetscInt oet = oer + (k - 1); 6122 const PetscInt oel = oet + (k - 1); 6123 const PetscInt ovlb = oel + (k - 1); 6124 const PetscInt ovrb = ovlb + 1; 6125 const PetscInt ovrt = ovrb + 1; 6126 const PetscInt ovlt = ovrt + 1; 6127 PetscInt o; 6128 6129 /* bottom */ 6130 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6131 for (o = oeb; o < oer; ++o) 6132 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6133 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6134 /* middle */ 6135 for (i = 0; i < k - 1; ++i) { 6136 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6137 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6138 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6139 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6140 } 6141 /* top */ 6142 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6143 for (o = oel - 1; o >= oet; --o) 6144 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6145 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6146 foffset = offset; 6147 } else { 6148 PetscInt dof; 6149 6150 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6151 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6152 foffset = offset; 6153 } 6154 break; 6155 case 3: 6156 /* The original hex closure is 6157 6158 {c, 6159 f_b, f_t, f_f, f_b, f_r, f_l, 6160 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6161 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6162 */ 6163 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6164 if (!continuous && d < dim) continue; 6165 /* The SEM order is 6166 Bottom Slice 6167 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6168 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6169 v_blb, {e_bb}, v_brb, 6170 6171 Middle Slice (j) 6172 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6173 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6174 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6175 6176 Top Slice 6177 v_tlf, {e_tf}, v_trf, 6178 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6179 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6180 */ 6181 if (continuous) { 6182 const PetscInt oc = 0; 6183 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6184 const PetscInt oft = ofb + PetscSqr(k - 1); 6185 const PetscInt off = oft + PetscSqr(k - 1); 6186 const PetscInt ofk = off + PetscSqr(k - 1); 6187 const PetscInt ofr = ofk + PetscSqr(k - 1); 6188 const PetscInt ofl = ofr + PetscSqr(k - 1); 6189 const PetscInt oebl = ofl + PetscSqr(k - 1); 6190 const PetscInt oebb = oebl + (k - 1); 6191 const PetscInt oebr = oebb + (k - 1); 6192 const PetscInt oebf = oebr + (k - 1); 6193 const PetscInt oetf = oebf + (k - 1); 6194 const PetscInt oetr = oetf + (k - 1); 6195 const PetscInt oetb = oetr + (k - 1); 6196 const PetscInt oetl = oetb + (k - 1); 6197 const PetscInt oerf = oetl + (k - 1); 6198 const PetscInt oelf = oerf + (k - 1); 6199 const PetscInt oelb = oelf + (k - 1); 6200 const PetscInt oerb = oelb + (k - 1); 6201 const PetscInt ovblf = oerb + (k - 1); 6202 const PetscInt ovblb = ovblf + 1; 6203 const PetscInt ovbrb = ovblb + 1; 6204 const PetscInt ovbrf = ovbrb + 1; 6205 const PetscInt ovtlf = ovbrf + 1; 6206 const PetscInt ovtrf = ovtlf + 1; 6207 const PetscInt ovtrb = ovtrf + 1; 6208 const PetscInt ovtlb = ovtrb + 1; 6209 PetscInt o, n; 6210 6211 /* Bottom Slice */ 6212 /* bottom */ 6213 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6214 for (o = oetf - 1; o >= oebf; --o) 6215 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6216 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6217 /* middle */ 6218 for (i = 0; i < k - 1; ++i) { 6219 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6220 for (n = 0; n < k - 1; ++n) { 6221 o = ofb + n * (k - 1) + i; 6222 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6223 } 6224 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6225 } 6226 /* top */ 6227 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6228 for (o = oebb; o < oebr; ++o) 6229 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6230 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6231 6232 /* Middle Slice */ 6233 for (j = 0; j < k - 1; ++j) { 6234 /* bottom */ 6235 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6236 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6237 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6238 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6239 /* middle */ 6240 for (i = 0; i < k - 1; ++i) { 6241 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6242 for (n = 0; n < k - 1; ++n) 6243 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6244 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6245 } 6246 /* top */ 6247 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6248 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6249 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6250 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6251 } 6252 6253 /* Top Slice */ 6254 /* bottom */ 6255 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6256 for (o = oetf; o < oetr; ++o) 6257 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6258 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6259 /* middle */ 6260 for (i = 0; i < k - 1; ++i) { 6261 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6262 for (n = 0; n < k - 1; ++n) 6263 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6264 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6265 } 6266 /* top */ 6267 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6268 for (o = oetl - 1; o >= oetb; --o) 6269 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6270 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6271 6272 foffset = offset; 6273 } else { 6274 PetscInt dof; 6275 6276 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6277 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6278 foffset = offset; 6279 } 6280 break; 6281 default: 6282 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6283 } 6284 } 6285 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6286 /* Check permutation */ 6287 { 6288 PetscInt *check; 6289 6290 PetscCall(PetscMalloc1(size, &check)); 6291 for (i = 0; i < size; ++i) { 6292 check[i] = -1; 6293 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6294 } 6295 for (i = 0; i < size; ++i) check[perm[i]] = i; 6296 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6297 PetscCall(PetscFree(check)); 6298 } 6299 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6300 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6301 PetscInt *loc_perm; 6302 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6303 for (PetscInt i = 0; i < size; i++) { 6304 loc_perm[i] = perm[i]; 6305 loc_perm[size + i] = size + perm[i]; 6306 } 6307 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6308 } 6309 } 6310 PetscFunctionReturn(PETSC_SUCCESS); 6311 } 6312 6313 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6314 { 6315 PetscDS prob; 6316 PetscInt depth, Nf, h; 6317 DMLabel label; 6318 6319 PetscFunctionBeginHot; 6320 PetscCall(DMGetDS(dm, &prob)); 6321 Nf = prob->Nf; 6322 label = dm->depthLabel; 6323 *dspace = NULL; 6324 if (field < Nf) { 6325 PetscObject disc = prob->disc[field]; 6326 6327 if (disc->classid == PETSCFE_CLASSID) { 6328 PetscDualSpace dsp; 6329 6330 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6331 PetscCall(DMLabelGetNumValues(label, &depth)); 6332 PetscCall(DMLabelGetValue(label, point, &h)); 6333 h = depth - 1 - h; 6334 if (h) { 6335 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6336 } else { 6337 *dspace = dsp; 6338 } 6339 } 6340 } 6341 PetscFunctionReturn(PETSC_SUCCESS); 6342 } 6343 6344 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6345 { 6346 PetscScalar *array; 6347 const PetscScalar *vArray; 6348 const PetscInt *cone, *coneO; 6349 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6350 6351 PetscFunctionBeginHot; 6352 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6353 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6354 PetscCall(DMPlexGetCone(dm, point, &cone)); 6355 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6356 if (!values || !*values) { 6357 if ((point >= pStart) && (point < pEnd)) { 6358 PetscInt dof; 6359 6360 PetscCall(PetscSectionGetDof(section, point, &dof)); 6361 size += dof; 6362 } 6363 for (p = 0; p < numPoints; ++p) { 6364 const PetscInt cp = cone[p]; 6365 PetscInt dof; 6366 6367 if ((cp < pStart) || (cp >= pEnd)) continue; 6368 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6369 size += dof; 6370 } 6371 if (!values) { 6372 if (csize) *csize = size; 6373 PetscFunctionReturn(PETSC_SUCCESS); 6374 } 6375 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6376 } else { 6377 array = *values; 6378 } 6379 size = 0; 6380 PetscCall(VecGetArrayRead(v, &vArray)); 6381 if ((point >= pStart) && (point < pEnd)) { 6382 PetscInt dof, off, d; 6383 const PetscScalar *varr; 6384 6385 PetscCall(PetscSectionGetDof(section, point, &dof)); 6386 PetscCall(PetscSectionGetOffset(section, point, &off)); 6387 varr = PetscSafePointerPlusOffset(vArray, off); 6388 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6389 size += dof; 6390 } 6391 for (p = 0; p < numPoints; ++p) { 6392 const PetscInt cp = cone[p]; 6393 PetscInt o = coneO[p]; 6394 PetscInt dof, off, d; 6395 const PetscScalar *varr; 6396 6397 if ((cp < pStart) || (cp >= pEnd)) continue; 6398 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6399 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6400 varr = PetscSafePointerPlusOffset(vArray, off); 6401 if (o >= 0) { 6402 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6403 } else { 6404 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6405 } 6406 size += dof; 6407 } 6408 PetscCall(VecRestoreArrayRead(v, &vArray)); 6409 if (!*values) { 6410 if (csize) *csize = size; 6411 *values = array; 6412 } else { 6413 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6414 *csize = size; 6415 } 6416 PetscFunctionReturn(PETSC_SUCCESS); 6417 } 6418 6419 /* Compress out points not in the section */ 6420 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6421 { 6422 const PetscInt np = *numPoints; 6423 PetscInt pStart, pEnd, p, q; 6424 6425 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6426 for (p = 0, q = 0; p < np; ++p) { 6427 const PetscInt r = points[p * 2]; 6428 if ((r >= pStart) && (r < pEnd)) { 6429 points[q * 2] = r; 6430 points[q * 2 + 1] = points[p * 2 + 1]; 6431 ++q; 6432 } 6433 } 6434 *numPoints = q; 6435 return PETSC_SUCCESS; 6436 } 6437 6438 /* Compressed closure does not apply closure permutation */ 6439 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6440 { 6441 const PetscInt *cla = NULL; 6442 PetscInt np, *pts = NULL; 6443 6444 PetscFunctionBeginHot; 6445 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6446 if (!ornt && *clPoints) { 6447 PetscInt dof, off; 6448 6449 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6450 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6451 PetscCall(ISGetIndices(*clPoints, &cla)); 6452 np = dof / 2; 6453 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6454 } else { 6455 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6456 PetscCall(CompressPoints_Private(section, &np, pts)); 6457 } 6458 *numPoints = np; 6459 *points = pts; 6460 *clp = cla; 6461 PetscFunctionReturn(PETSC_SUCCESS); 6462 } 6463 6464 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6465 { 6466 PetscFunctionBeginHot; 6467 if (!*clPoints) { 6468 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6469 } else { 6470 PetscCall(ISRestoreIndices(*clPoints, clp)); 6471 } 6472 *numPoints = 0; 6473 *points = NULL; 6474 *clSec = NULL; 6475 *clPoints = NULL; 6476 *clp = NULL; 6477 PetscFunctionReturn(PETSC_SUCCESS); 6478 } 6479 6480 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6481 { 6482 PetscInt offset = 0, p; 6483 const PetscInt **perms = NULL; 6484 const PetscScalar **flips = NULL; 6485 6486 PetscFunctionBeginHot; 6487 *size = 0; 6488 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6489 for (p = 0; p < numPoints; p++) { 6490 const PetscInt point = points[2 * p]; 6491 const PetscInt *perm = perms ? perms[p] : NULL; 6492 const PetscScalar *flip = flips ? flips[p] : NULL; 6493 PetscInt dof, off, d; 6494 const PetscScalar *varr; 6495 6496 PetscCall(PetscSectionGetDof(section, point, &dof)); 6497 PetscCall(PetscSectionGetOffset(section, point, &off)); 6498 varr = PetscSafePointerPlusOffset(vArray, off); 6499 if (clperm) { 6500 if (perm) { 6501 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6502 } else { 6503 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6504 } 6505 if (flip) { 6506 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6507 } 6508 } else { 6509 if (perm) { 6510 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6511 } else { 6512 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6513 } 6514 if (flip) { 6515 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6516 } 6517 } 6518 offset += dof; 6519 } 6520 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6521 *size = offset; 6522 PetscFunctionReturn(PETSC_SUCCESS); 6523 } 6524 6525 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[]) 6526 { 6527 PetscInt offset = 0, f; 6528 6529 PetscFunctionBeginHot; 6530 *size = 0; 6531 for (f = 0; f < numFields; ++f) { 6532 PetscInt p; 6533 const PetscInt **perms = NULL; 6534 const PetscScalar **flips = NULL; 6535 6536 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6537 for (p = 0; p < numPoints; p++) { 6538 const PetscInt point = points[2 * p]; 6539 PetscInt fdof, foff, b; 6540 const PetscScalar *varr; 6541 const PetscInt *perm = perms ? perms[p] : NULL; 6542 const PetscScalar *flip = flips ? flips[p] : NULL; 6543 6544 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6545 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6546 varr = &vArray[foff]; 6547 if (clperm) { 6548 if (perm) { 6549 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6550 } else { 6551 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6552 } 6553 if (flip) { 6554 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6555 } 6556 } else { 6557 if (perm) { 6558 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6559 } else { 6560 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6561 } 6562 if (flip) { 6563 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6564 } 6565 } 6566 offset += fdof; 6567 } 6568 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6569 } 6570 *size = offset; 6571 PetscFunctionReturn(PETSC_SUCCESS); 6572 } 6573 6574 /*@C 6575 DMPlexVecGetOrientedClosure - Get an array of the values on the closure of 'point' with a given orientation, optionally applying the closure permutation. 6576 6577 Not collective 6578 6579 Input Parameters: 6580 + dm - The `DM` 6581 . section - The section describing the layout in `v`, or `NULL` to use the default section 6582 . useClPerm - Flag for whether the provided closure permutation should be applied to the values 6583 . v - The local vector 6584 . point - The point in the `DM` 6585 - ornt - The orientation of the cell, an integer giving the prescription for cone traversal. Typically, this will be 0. 6586 6587 Input/Output Parameters: 6588 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6589 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6590 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6591 6592 Level: advanced 6593 6594 Notes: 6595 `DMPlexVecGetOrientedClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6596 calling function. This is because `DMPlexVecGetOrientedClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6597 assembly function, and a user may already have allocated storage for this operation. 6598 6599 Fortran Notes: 6600 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6601 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6602 6603 `values` must be declared with 6604 .vb 6605 PetscScalar,dimension(:),pointer :: values 6606 .ve 6607 and it will be allocated internally by PETSc to hold the values returned 6608 6609 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexGetCellCoordinates()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()` 6610 @*/ 6611 PetscErrorCode DMPlexVecGetOrientedClosure(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6612 { 6613 PetscSection clSection; 6614 IS clPoints; 6615 PetscInt *points = NULL; 6616 const PetscInt *clp, *perm = NULL; 6617 PetscInt depth, numFields, numPoints, asize; 6618 6619 PetscFunctionBeginHot; 6620 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6621 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6622 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6623 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6624 PetscCall(DMPlexGetDepth(dm, &depth)); 6625 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6626 if (depth == 1 && numFields < 2) { 6627 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6628 PetscFunctionReturn(PETSC_SUCCESS); 6629 } 6630 /* Get points */ 6631 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6632 /* Get sizes */ 6633 asize = 0; 6634 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6635 PetscInt dof; 6636 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6637 asize += dof; 6638 } 6639 if (values) { 6640 const PetscScalar *vArray; 6641 PetscInt size; 6642 6643 if (*values) { 6644 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); 6645 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6646 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6647 PetscCall(VecGetArrayRead(v, &vArray)); 6648 /* Get values */ 6649 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6650 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6651 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6652 /* Cleanup array */ 6653 PetscCall(VecRestoreArrayRead(v, &vArray)); 6654 } 6655 if (csize) *csize = asize; 6656 /* Cleanup points */ 6657 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6658 PetscFunctionReturn(PETSC_SUCCESS); 6659 } 6660 6661 /*@C 6662 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6663 6664 Not collective 6665 6666 Input Parameters: 6667 + dm - The `DM` 6668 . section - The section describing the layout in `v`, or `NULL` to use the default section 6669 . v - The local vector 6670 - point - The point in the `DM` 6671 6672 Input/Output Parameters: 6673 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6674 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6675 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6676 6677 Level: intermediate 6678 6679 Notes: 6680 This is used for getting the all values in a `Vec` in the closure of a mesh point. 6681 To get only the values in the closure of a mesh point at a specific depth (for example, at mesh vertices), use `DMPlexVecGetClosureAtDepth()`. 6682 6683 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6684 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6685 assembly function, and a user may already have allocated storage for this operation. 6686 6687 A typical use could be 6688 .vb 6689 values = NULL; 6690 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6691 for (cl = 0; cl < clSize; ++cl) { 6692 <Compute on closure> 6693 } 6694 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6695 .ve 6696 or 6697 .vb 6698 PetscMalloc1(clMaxSize, &values); 6699 for (p = pStart; p < pEnd; ++p) { 6700 clSize = clMaxSize; 6701 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6702 for (cl = 0; cl < clSize; ++cl) { 6703 <Compute on closure> 6704 } 6705 } 6706 PetscFree(values); 6707 .ve 6708 6709 Fortran Notes: 6710 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6711 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6712 6713 `values` must be declared with 6714 .vb 6715 PetscScalar,dimension(:),pointer :: values 6716 .ve 6717 and it will be allocated internally by PETSc to hold the values returned 6718 6719 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosureAtDepth()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6720 @*/ 6721 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6722 { 6723 PetscFunctionBeginHot; 6724 PetscCall(DMPlexVecGetOrientedClosure(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6725 PetscFunctionReturn(PETSC_SUCCESS); 6726 } 6727 6728 /*@C 6729 DMPlexVecGetClosureAtDepth - Get an array of the values on the closure of 'point' that are at a specific depth 6730 6731 Not collective 6732 6733 Input Parameters: 6734 + dm - The `DM` 6735 . section - The section describing the layout in `v`, or `NULL` to use the default section 6736 . v - The local vector 6737 . depth - The depth of mesh points that should be returned 6738 - point - The point in the `DM` 6739 6740 Input/Output Parameters: 6741 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6742 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6743 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6744 6745 Level: intermediate 6746 6747 Notes: 6748 This is used for getting the values in a `Vec` associated with specific mesh points. 6749 For example, to get only the values at mesh vertices, pass `depth=0`. To get all the values in the closure of a mesh point, use `DMPlexVecGetClosure()`. 6750 6751 `DMPlexVecGetClosureAtDepth()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6752 calling function. This is because `DMPlexVecGetClosureAtDepth()` is typically called in the inner loop of a `Vec` or `Mat` 6753 assembly function, and a user may already have allocated storage for this operation. 6754 6755 A typical use could be 6756 .vb 6757 values = NULL; 6758 PetscCall(DMPlexVecGetClosureAtDepth(dm, NULL, v, p, depth, &clSize, &values)); 6759 for (cl = 0; cl < clSize; ++cl) { 6760 <Compute on closure> 6761 } 6762 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6763 .ve 6764 or 6765 .vb 6766 PetscMalloc1(clMaxSize, &values); 6767 for (p = pStart; p < pEnd; ++p) { 6768 clSize = clMaxSize; 6769 PetscCall(DMPlexVecGetClosureAtDepth(dm, NULL, v, p, depth, &clSize, &values)); 6770 for (cl = 0; cl < clSize; ++cl) { 6771 <Compute on closure> 6772 } 6773 } 6774 PetscFree(values); 6775 .ve 6776 6777 Fortran Notes: 6778 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6779 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6780 6781 `values` must be declared with 6782 .vb 6783 PetscScalar,dimension(:),pointer :: values 6784 .ve 6785 and it will be allocated internally by PETSc to hold the values returned 6786 6787 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6788 @*/ 6789 PetscErrorCode DMPlexVecGetClosureAtDepth(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6790 { 6791 DMLabel depthLabel; 6792 PetscSection clSection; 6793 IS clPoints; 6794 PetscScalar *array; 6795 const PetscScalar *vArray; 6796 PetscInt *points = NULL; 6797 const PetscInt *clp, *perm = NULL; 6798 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6799 6800 PetscFunctionBeginHot; 6801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6802 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6803 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6804 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6805 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6806 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6807 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6808 if (mdepth == 1 && numFields < 2) { 6809 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6810 PetscFunctionReturn(PETSC_SUCCESS); 6811 } 6812 /* Get points */ 6813 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6814 for (clsize = 0, p = 0; p < Np; p++) { 6815 PetscInt dof; 6816 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6817 clsize += dof; 6818 } 6819 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6820 /* Filter points */ 6821 for (p = 0; p < numPoints * 2; p += 2) { 6822 PetscInt dep; 6823 6824 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6825 if (dep != depth) continue; 6826 points[Np * 2 + 0] = points[p]; 6827 points[Np * 2 + 1] = points[p + 1]; 6828 ++Np; 6829 } 6830 /* Get array */ 6831 if (!values || !*values) { 6832 PetscInt asize = 0, dof; 6833 6834 for (p = 0; p < Np * 2; p += 2) { 6835 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6836 asize += dof; 6837 } 6838 if (!values) { 6839 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6840 if (csize) *csize = asize; 6841 PetscFunctionReturn(PETSC_SUCCESS); 6842 } 6843 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6844 } else { 6845 array = *values; 6846 } 6847 PetscCall(VecGetArrayRead(v, &vArray)); 6848 /* Get values */ 6849 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6850 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6851 /* Cleanup points */ 6852 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6853 /* Cleanup array */ 6854 PetscCall(VecRestoreArrayRead(v, &vArray)); 6855 if (!*values) { 6856 if (csize) *csize = size; 6857 *values = array; 6858 } else { 6859 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6860 *csize = size; 6861 } 6862 PetscFunctionReturn(PETSC_SUCCESS); 6863 } 6864 6865 /*@C 6866 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6867 6868 Not collective 6869 6870 Input Parameters: 6871 + dm - The `DM` 6872 . section - The section describing the layout in `v`, or `NULL` to use the default section 6873 . v - The local vector 6874 . point - The point in the `DM` 6875 . csize - The number of values in the closure, or `NULL` 6876 - values - The array of values 6877 6878 Level: intermediate 6879 6880 Note: 6881 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6882 6883 Fortran Note: 6884 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6885 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6886 6887 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6888 @*/ 6889 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6890 { 6891 PetscInt size = 0; 6892 6893 PetscFunctionBegin; 6894 /* Should work without recalculating size */ 6895 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6896 *values = NULL; 6897 PetscFunctionReturn(PETSC_SUCCESS); 6898 } 6899 6900 static inline void add(PetscScalar *x, PetscScalar y) 6901 { 6902 *x += y; 6903 } 6904 static inline void insert(PetscScalar *x, PetscScalar y) 6905 { 6906 *x = y; 6907 } 6908 6909 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[]) 6910 { 6911 PetscInt cdof; /* The number of constraints on this point */ 6912 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6913 PetscScalar *a; 6914 PetscInt off, cind = 0, k; 6915 6916 PetscFunctionBegin; 6917 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6918 PetscCall(PetscSectionGetOffset(section, point, &off)); 6919 a = &array[off]; 6920 if (!cdof || setBC) { 6921 if (clperm) { 6922 if (perm) { 6923 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6924 } else { 6925 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6926 } 6927 } else { 6928 if (perm) { 6929 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6930 } else { 6931 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6932 } 6933 } 6934 } else { 6935 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6936 if (clperm) { 6937 if (perm) { 6938 for (k = 0; k < dof; ++k) { 6939 if ((cind < cdof) && (k == cdofs[cind])) { 6940 ++cind; 6941 continue; 6942 } 6943 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6944 } 6945 } else { 6946 for (k = 0; k < dof; ++k) { 6947 if ((cind < cdof) && (k == cdofs[cind])) { 6948 ++cind; 6949 continue; 6950 } 6951 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6952 } 6953 } 6954 } else { 6955 if (perm) { 6956 for (k = 0; k < dof; ++k) { 6957 if ((cind < cdof) && (k == cdofs[cind])) { 6958 ++cind; 6959 continue; 6960 } 6961 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6962 } 6963 } else { 6964 for (k = 0; k < dof; ++k) { 6965 if ((cind < cdof) && (k == cdofs[cind])) { 6966 ++cind; 6967 continue; 6968 } 6969 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6970 } 6971 } 6972 } 6973 } 6974 PetscFunctionReturn(PETSC_SUCCESS); 6975 } 6976 6977 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[]) 6978 { 6979 PetscInt cdof; /* The number of constraints on this point */ 6980 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6981 PetscScalar *a; 6982 PetscInt off, cind = 0, k; 6983 6984 PetscFunctionBegin; 6985 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6986 PetscCall(PetscSectionGetOffset(section, point, &off)); 6987 a = &array[off]; 6988 if (cdof) { 6989 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6990 if (clperm) { 6991 if (perm) { 6992 for (k = 0; k < dof; ++k) { 6993 if ((cind < cdof) && (k == cdofs[cind])) { 6994 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6995 cind++; 6996 } 6997 } 6998 } else { 6999 for (k = 0; k < dof; ++k) { 7000 if ((cind < cdof) && (k == cdofs[cind])) { 7001 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 7002 cind++; 7003 } 7004 } 7005 } 7006 } else { 7007 if (perm) { 7008 for (k = 0; k < dof; ++k) { 7009 if ((cind < cdof) && (k == cdofs[cind])) { 7010 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 7011 cind++; 7012 } 7013 } 7014 } else { 7015 for (k = 0; k < dof; ++k) { 7016 if ((cind < cdof) && (k == cdofs[cind])) { 7017 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 7018 cind++; 7019 } 7020 } 7021 } 7022 } 7023 } 7024 PetscFunctionReturn(PETSC_SUCCESS); 7025 } 7026 7027 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[]) 7028 { 7029 PetscScalar *a; 7030 PetscInt fdof, foff, fcdof, foffset = *offset; 7031 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7032 PetscInt cind = 0, b; 7033 7034 PetscFunctionBegin; 7035 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7036 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 7037 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 7038 a = &array[foff]; 7039 if (!fcdof || setBC) { 7040 if (clperm) { 7041 if (perm) { 7042 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7043 } else { 7044 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7045 } 7046 } else { 7047 if (perm) { 7048 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7049 } else { 7050 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7051 } 7052 } 7053 } else { 7054 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7055 if (clperm) { 7056 if (perm) { 7057 for (b = 0; b < fdof; b++) { 7058 if ((cind < fcdof) && (b == fcdofs[cind])) { 7059 ++cind; 7060 continue; 7061 } 7062 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7063 } 7064 } else { 7065 for (b = 0; b < fdof; b++) { 7066 if ((cind < fcdof) && (b == fcdofs[cind])) { 7067 ++cind; 7068 continue; 7069 } 7070 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7071 } 7072 } 7073 } else { 7074 if (perm) { 7075 for (b = 0; b < fdof; b++) { 7076 if ((cind < fcdof) && (b == fcdofs[cind])) { 7077 ++cind; 7078 continue; 7079 } 7080 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7081 } 7082 } else { 7083 for (b = 0; b < fdof; b++) { 7084 if ((cind < fcdof) && (b == fcdofs[cind])) { 7085 ++cind; 7086 continue; 7087 } 7088 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7089 } 7090 } 7091 } 7092 } 7093 *offset += fdof; 7094 PetscFunctionReturn(PETSC_SUCCESS); 7095 } 7096 7097 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[]) 7098 { 7099 PetscScalar *a; 7100 PetscInt fdof, foff, fcdof, foffset = *offset; 7101 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7102 PetscInt Nc, cind = 0, ncind = 0, b; 7103 PetscBool ncSet, fcSet; 7104 7105 PetscFunctionBegin; 7106 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 7107 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7108 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 7109 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 7110 a = &array[foff]; 7111 if (fcdof) { 7112 /* We just override fcdof and fcdofs with Ncc and comps */ 7113 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7114 if (clperm) { 7115 if (perm) { 7116 if (comps) { 7117 for (b = 0; b < fdof; b++) { 7118 ncSet = fcSet = PETSC_FALSE; 7119 if (b % Nc == comps[ncind]) { 7120 ncind = (ncind + 1) % Ncc; 7121 ncSet = PETSC_TRUE; 7122 } 7123 if ((cind < fcdof) && (b == fcdofs[cind])) { 7124 ++cind; 7125 fcSet = PETSC_TRUE; 7126 } 7127 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7128 } 7129 } else { 7130 for (b = 0; b < fdof; b++) { 7131 if ((cind < fcdof) && (b == fcdofs[cind])) { 7132 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7133 ++cind; 7134 } 7135 } 7136 } 7137 } else { 7138 if (comps) { 7139 for (b = 0; b < fdof; b++) { 7140 ncSet = fcSet = PETSC_FALSE; 7141 if (b % Nc == comps[ncind]) { 7142 ncind = (ncind + 1) % Ncc; 7143 ncSet = PETSC_TRUE; 7144 } 7145 if ((cind < fcdof) && (b == fcdofs[cind])) { 7146 ++cind; 7147 fcSet = PETSC_TRUE; 7148 } 7149 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7150 } 7151 } else { 7152 for (b = 0; b < fdof; b++) { 7153 if ((cind < fcdof) && (b == fcdofs[cind])) { 7154 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7155 ++cind; 7156 } 7157 } 7158 } 7159 } 7160 } else { 7161 if (perm) { 7162 if (comps) { 7163 for (b = 0; b < fdof; b++) { 7164 ncSet = fcSet = PETSC_FALSE; 7165 if (b % Nc == comps[ncind]) { 7166 ncind = (ncind + 1) % Ncc; 7167 ncSet = PETSC_TRUE; 7168 } 7169 if ((cind < fcdof) && (b == fcdofs[cind])) { 7170 ++cind; 7171 fcSet = PETSC_TRUE; 7172 } 7173 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7174 } 7175 } else { 7176 for (b = 0; b < fdof; b++) { 7177 if ((cind < fcdof) && (b == fcdofs[cind])) { 7178 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7179 ++cind; 7180 } 7181 } 7182 } 7183 } else { 7184 if (comps) { 7185 for (b = 0; b < fdof; b++) { 7186 ncSet = fcSet = PETSC_FALSE; 7187 if (b % Nc == comps[ncind]) { 7188 ncind = (ncind + 1) % Ncc; 7189 ncSet = PETSC_TRUE; 7190 } 7191 if ((cind < fcdof) && (b == fcdofs[cind])) { 7192 ++cind; 7193 fcSet = PETSC_TRUE; 7194 } 7195 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7196 } 7197 } else { 7198 for (b = 0; b < fdof; b++) { 7199 if ((cind < fcdof) && (b == fcdofs[cind])) { 7200 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7201 ++cind; 7202 } 7203 } 7204 } 7205 } 7206 } 7207 } 7208 *offset += fdof; 7209 PetscFunctionReturn(PETSC_SUCCESS); 7210 } 7211 7212 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7213 { 7214 PetscScalar *array; 7215 const PetscInt *cone, *coneO; 7216 PetscInt pStart, pEnd, p, numPoints, off, dof; 7217 7218 PetscFunctionBeginHot; 7219 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7220 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7221 PetscCall(DMPlexGetCone(dm, point, &cone)); 7222 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7223 PetscCall(VecGetArray(v, &array)); 7224 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7225 const PetscInt cp = !p ? point : cone[p - 1]; 7226 const PetscInt o = !p ? 0 : coneO[p - 1]; 7227 7228 if ((cp < pStart) || (cp >= pEnd)) { 7229 dof = 0; 7230 continue; 7231 } 7232 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7233 /* ADD_VALUES */ 7234 { 7235 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7236 PetscScalar *a; 7237 PetscInt cdof, coff, cind = 0, k; 7238 7239 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7240 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7241 a = &array[coff]; 7242 if (!cdof) { 7243 if (o >= 0) { 7244 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7245 } else { 7246 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7247 } 7248 } else { 7249 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7250 if (o >= 0) { 7251 for (k = 0; k < dof; ++k) { 7252 if ((cind < cdof) && (k == cdofs[cind])) { 7253 ++cind; 7254 continue; 7255 } 7256 a[k] += values[off + k]; 7257 } 7258 } else { 7259 for (k = 0; k < dof; ++k) { 7260 if ((cind < cdof) && (k == cdofs[cind])) { 7261 ++cind; 7262 continue; 7263 } 7264 a[k] += values[off + dof - k - 1]; 7265 } 7266 } 7267 } 7268 } 7269 } 7270 PetscCall(VecRestoreArray(v, &array)); 7271 PetscFunctionReturn(PETSC_SUCCESS); 7272 } 7273 7274 /*@C 7275 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7276 7277 Not collective 7278 7279 Input Parameters: 7280 + dm - The `DM` 7281 . section - The section describing the layout in `v`, or `NULL` to use the default section 7282 . v - The local vector 7283 . point - The point in the `DM` 7284 . values - The array of values 7285 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7286 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7287 7288 Level: intermediate 7289 7290 Note: 7291 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7292 7293 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7294 @*/ 7295 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7296 { 7297 PetscSection clSection; 7298 IS clPoints; 7299 PetscScalar *array; 7300 PetscInt *points = NULL; 7301 const PetscInt *clp, *clperm = NULL; 7302 PetscInt depth, numFields, numPoints, p, clsize; 7303 7304 PetscFunctionBeginHot; 7305 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7306 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7307 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7308 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7309 PetscCall(DMPlexGetDepth(dm, &depth)); 7310 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7311 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7312 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7313 PetscFunctionReturn(PETSC_SUCCESS); 7314 } 7315 /* Get points */ 7316 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7317 for (clsize = 0, p = 0; p < numPoints; p++) { 7318 PetscInt dof; 7319 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7320 clsize += dof; 7321 } 7322 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7323 /* Get array */ 7324 PetscCall(VecGetArray(v, &array)); 7325 /* Get values */ 7326 if (numFields > 0) { 7327 PetscInt offset = 0, f; 7328 for (f = 0; f < numFields; ++f) { 7329 const PetscInt **perms = NULL; 7330 const PetscScalar **flips = NULL; 7331 7332 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7333 switch (mode) { 7334 case INSERT_VALUES: 7335 for (p = 0; p < numPoints; p++) { 7336 const PetscInt point = points[2 * p]; 7337 const PetscInt *perm = perms ? perms[p] : NULL; 7338 const PetscScalar *flip = flips ? flips[p] : NULL; 7339 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7340 } 7341 break; 7342 case INSERT_ALL_VALUES: 7343 for (p = 0; p < numPoints; p++) { 7344 const PetscInt point = points[2 * p]; 7345 const PetscInt *perm = perms ? perms[p] : NULL; 7346 const PetscScalar *flip = flips ? flips[p] : NULL; 7347 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7348 } 7349 break; 7350 case INSERT_BC_VALUES: 7351 for (p = 0; p < numPoints; p++) { 7352 const PetscInt point = points[2 * p]; 7353 const PetscInt *perm = perms ? perms[p] : NULL; 7354 const PetscScalar *flip = flips ? flips[p] : NULL; 7355 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7356 } 7357 break; 7358 case ADD_VALUES: 7359 for (p = 0; p < numPoints; p++) { 7360 const PetscInt point = points[2 * p]; 7361 const PetscInt *perm = perms ? perms[p] : NULL; 7362 const PetscScalar *flip = flips ? flips[p] : NULL; 7363 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7364 } 7365 break; 7366 case ADD_ALL_VALUES: 7367 for (p = 0; p < numPoints; p++) { 7368 const PetscInt point = points[2 * p]; 7369 const PetscInt *perm = perms ? perms[p] : NULL; 7370 const PetscScalar *flip = flips ? flips[p] : NULL; 7371 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7372 } 7373 break; 7374 case ADD_BC_VALUES: 7375 for (p = 0; p < numPoints; p++) { 7376 const PetscInt point = points[2 * p]; 7377 const PetscInt *perm = perms ? perms[p] : NULL; 7378 const PetscScalar *flip = flips ? flips[p] : NULL; 7379 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7380 } 7381 break; 7382 default: 7383 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7384 } 7385 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7386 } 7387 } else { 7388 PetscInt dof, off; 7389 const PetscInt **perms = NULL; 7390 const PetscScalar **flips = NULL; 7391 7392 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7393 switch (mode) { 7394 case INSERT_VALUES: 7395 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7396 const PetscInt point = points[2 * p]; 7397 const PetscInt *perm = perms ? perms[p] : NULL; 7398 const PetscScalar *flip = flips ? flips[p] : NULL; 7399 PetscCall(PetscSectionGetDof(section, point, &dof)); 7400 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7401 } 7402 break; 7403 case INSERT_ALL_VALUES: 7404 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7405 const PetscInt point = points[2 * p]; 7406 const PetscInt *perm = perms ? perms[p] : NULL; 7407 const PetscScalar *flip = flips ? flips[p] : NULL; 7408 PetscCall(PetscSectionGetDof(section, point, &dof)); 7409 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7410 } 7411 break; 7412 case INSERT_BC_VALUES: 7413 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7414 const PetscInt point = points[2 * p]; 7415 const PetscInt *perm = perms ? perms[p] : NULL; 7416 const PetscScalar *flip = flips ? flips[p] : NULL; 7417 PetscCall(PetscSectionGetDof(section, point, &dof)); 7418 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7419 } 7420 break; 7421 case ADD_VALUES: 7422 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7423 const PetscInt point = points[2 * p]; 7424 const PetscInt *perm = perms ? perms[p] : NULL; 7425 const PetscScalar *flip = flips ? flips[p] : NULL; 7426 PetscCall(PetscSectionGetDof(section, point, &dof)); 7427 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7428 } 7429 break; 7430 case ADD_ALL_VALUES: 7431 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7432 const PetscInt point = points[2 * p]; 7433 const PetscInt *perm = perms ? perms[p] : NULL; 7434 const PetscScalar *flip = flips ? flips[p] : NULL; 7435 PetscCall(PetscSectionGetDof(section, point, &dof)); 7436 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7437 } 7438 break; 7439 case ADD_BC_VALUES: 7440 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7441 const PetscInt point = points[2 * p]; 7442 const PetscInt *perm = perms ? perms[p] : NULL; 7443 const PetscScalar *flip = flips ? flips[p] : NULL; 7444 PetscCall(PetscSectionGetDof(section, point, &dof)); 7445 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7446 } 7447 break; 7448 default: 7449 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7450 } 7451 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7452 } 7453 /* Cleanup points */ 7454 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7455 /* Cleanup array */ 7456 PetscCall(VecRestoreArray(v, &array)); 7457 PetscFunctionReturn(PETSC_SUCCESS); 7458 } 7459 7460 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7461 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7462 { 7463 PetscFunctionBegin; 7464 *contains = PETSC_TRUE; 7465 if (label) { 7466 PetscInt fdof; 7467 7468 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7469 if (!*contains) { 7470 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7471 *offset += fdof; 7472 PetscFunctionReturn(PETSC_SUCCESS); 7473 } 7474 } 7475 PetscFunctionReturn(PETSC_SUCCESS); 7476 } 7477 7478 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7479 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) 7480 { 7481 PetscSection clSection; 7482 IS clPoints; 7483 PetscScalar *array; 7484 PetscInt *points = NULL; 7485 const PetscInt *clp; 7486 PetscInt numFields, numPoints, p; 7487 PetscInt offset = 0, f; 7488 7489 PetscFunctionBeginHot; 7490 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7491 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7492 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7493 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7494 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7495 /* Get points */ 7496 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7497 /* Get array */ 7498 PetscCall(VecGetArray(v, &array)); 7499 /* Get values */ 7500 for (f = 0; f < numFields; ++f) { 7501 const PetscInt **perms = NULL; 7502 const PetscScalar **flips = NULL; 7503 PetscBool contains; 7504 7505 if (!fieldActive[f]) { 7506 for (p = 0; p < numPoints * 2; p += 2) { 7507 PetscInt fdof; 7508 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7509 offset += fdof; 7510 } 7511 continue; 7512 } 7513 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7514 switch (mode) { 7515 case INSERT_VALUES: 7516 for (p = 0; p < numPoints; p++) { 7517 const PetscInt point = points[2 * p]; 7518 const PetscInt *perm = perms ? perms[p] : NULL; 7519 const PetscScalar *flip = flips ? flips[p] : NULL; 7520 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7521 if (!contains) continue; 7522 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7523 } 7524 break; 7525 case INSERT_ALL_VALUES: 7526 for (p = 0; p < numPoints; p++) { 7527 const PetscInt point = points[2 * p]; 7528 const PetscInt *perm = perms ? perms[p] : NULL; 7529 const PetscScalar *flip = flips ? flips[p] : NULL; 7530 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7531 if (!contains) continue; 7532 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7533 } 7534 break; 7535 case INSERT_BC_VALUES: 7536 for (p = 0; p < numPoints; p++) { 7537 const PetscInt point = points[2 * p]; 7538 const PetscInt *perm = perms ? perms[p] : NULL; 7539 const PetscScalar *flip = flips ? flips[p] : NULL; 7540 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7541 if (!contains) continue; 7542 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7543 } 7544 break; 7545 case ADD_VALUES: 7546 for (p = 0; p < numPoints; p++) { 7547 const PetscInt point = points[2 * p]; 7548 const PetscInt *perm = perms ? perms[p] : NULL; 7549 const PetscScalar *flip = flips ? flips[p] : NULL; 7550 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7551 if (!contains) continue; 7552 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7553 } 7554 break; 7555 case ADD_ALL_VALUES: 7556 for (p = 0; p < numPoints; p++) { 7557 const PetscInt point = points[2 * p]; 7558 const PetscInt *perm = perms ? perms[p] : NULL; 7559 const PetscScalar *flip = flips ? flips[p] : NULL; 7560 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7561 if (!contains) continue; 7562 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7563 } 7564 break; 7565 default: 7566 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7567 } 7568 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7569 } 7570 /* Cleanup points */ 7571 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7572 /* Cleanup array */ 7573 PetscCall(VecRestoreArray(v, &array)); 7574 PetscFunctionReturn(PETSC_SUCCESS); 7575 } 7576 7577 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7578 { 7579 PetscMPIInt rank; 7580 PetscInt i, j; 7581 7582 PetscFunctionBegin; 7583 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7584 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7585 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7586 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7587 numCIndices = numCIndices ? numCIndices : numRIndices; 7588 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7589 for (i = 0; i < numRIndices; i++) { 7590 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7591 for (j = 0; j < numCIndices; j++) { 7592 #if defined(PETSC_USE_COMPLEX) 7593 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7594 #else 7595 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7596 #endif 7597 } 7598 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7599 } 7600 PetscFunctionReturn(PETSC_SUCCESS); 7601 } 7602 7603 /* 7604 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7605 7606 Input Parameters: 7607 + section - The section for this data layout 7608 . islocal - Is the section (and thus indices being requested) local or global? 7609 . point - The point contributing dofs with these indices 7610 . off - The global offset of this point 7611 . loff - The local offset of each field 7612 . setBC - The flag determining whether to include indices of boundary values 7613 . perm - A permutation of the dofs on this point, or NULL 7614 - indperm - A permutation of the entire indices array, or NULL 7615 7616 Output Parameter: 7617 . indices - Indices for dofs on this point 7618 7619 Level: developer 7620 7621 Note: The indices could be local or global, depending on the value of 'off'. 7622 */ 7623 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7624 { 7625 PetscInt dof; /* The number of unknowns on this point */ 7626 PetscInt cdof; /* The number of constraints on this point */ 7627 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7628 PetscInt cind = 0, k; 7629 7630 PetscFunctionBegin; 7631 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7632 PetscCall(PetscSectionGetDof(section, point, &dof)); 7633 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7634 if (!cdof || setBC) { 7635 for (k = 0; k < dof; ++k) { 7636 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7637 const PetscInt ind = indperm ? indperm[preind] : preind; 7638 7639 indices[ind] = off + k; 7640 } 7641 } else { 7642 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7643 for (k = 0; k < dof; ++k) { 7644 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7645 const PetscInt ind = indperm ? indperm[preind] : preind; 7646 7647 if ((cind < cdof) && (k == cdofs[cind])) { 7648 /* Insert check for returning constrained indices */ 7649 indices[ind] = -(off + k + 1); 7650 ++cind; 7651 } else { 7652 indices[ind] = off + k - (islocal ? 0 : cind); 7653 } 7654 } 7655 } 7656 *loff += dof; 7657 PetscFunctionReturn(PETSC_SUCCESS); 7658 } 7659 7660 /* 7661 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7662 7663 Input Parameters: 7664 + section - a section (global or local) 7665 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7666 . point - point within section 7667 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7668 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7669 . setBC - identify constrained (boundary condition) points via involution. 7670 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7671 . permsoff - offset 7672 - indperm - index permutation 7673 7674 Output Parameter: 7675 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7676 . indices - array to hold indices (as defined by section) of each dof associated with point 7677 7678 Notes: 7679 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7680 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7681 in the local vector. 7682 7683 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7684 significant). It is invalid to call with a global section and setBC=true. 7685 7686 Developer Note: 7687 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7688 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7689 offset could be obtained from the section instead of passing it explicitly as we do now. 7690 7691 Example: 7692 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7693 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7694 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7695 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. 7696 7697 Level: developer 7698 */ 7699 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[]) 7700 { 7701 PetscInt numFields, foff, f; 7702 7703 PetscFunctionBegin; 7704 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7705 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7706 for (f = 0, foff = 0; f < numFields; ++f) { 7707 PetscInt fdof, cfdof; 7708 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7709 PetscInt cind = 0, b; 7710 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7711 7712 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7713 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7714 if (!cfdof || setBC) { 7715 for (b = 0; b < fdof; ++b) { 7716 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7717 const PetscInt ind = indperm ? indperm[preind] : preind; 7718 7719 indices[ind] = off + foff + b; 7720 } 7721 } else { 7722 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7723 for (b = 0; b < fdof; ++b) { 7724 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7725 const PetscInt ind = indperm ? indperm[preind] : preind; 7726 7727 if ((cind < cfdof) && (b == fcdofs[cind])) { 7728 indices[ind] = -(off + foff + b + 1); 7729 ++cind; 7730 } else { 7731 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7732 } 7733 } 7734 } 7735 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7736 foffs[f] += fdof; 7737 } 7738 PetscFunctionReturn(PETSC_SUCCESS); 7739 } 7740 7741 /* 7742 This version believes the globalSection offsets for each field, rather than just the point offset 7743 7744 . foffs - The offset into 'indices' for each field, since it is segregated by field 7745 7746 Notes: 7747 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7748 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7749 */ 7750 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7751 { 7752 PetscInt numFields, foff, f; 7753 7754 PetscFunctionBegin; 7755 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7756 for (f = 0; f < numFields; ++f) { 7757 PetscInt fdof, cfdof; 7758 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7759 PetscInt cind = 0, b; 7760 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7761 7762 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7763 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7764 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7765 if (!cfdof) { 7766 for (b = 0; b < fdof; ++b) { 7767 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7768 const PetscInt ind = indperm ? indperm[preind] : preind; 7769 7770 indices[ind] = foff + b; 7771 } 7772 } else { 7773 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7774 for (b = 0; b < fdof; ++b) { 7775 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7776 const PetscInt ind = indperm ? indperm[preind] : preind; 7777 7778 if ((cind < cfdof) && (b == fcdofs[cind])) { 7779 indices[ind] = -(foff + b + 1); 7780 ++cind; 7781 } else { 7782 indices[ind] = foff + b - cind; 7783 } 7784 } 7785 } 7786 foffs[f] += fdof; 7787 } 7788 PetscFunctionReturn(PETSC_SUCCESS); 7789 } 7790 7791 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7792 { 7793 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7794 7795 PetscFunctionBegin; 7796 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7797 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7798 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7799 for (PetscInt p = 0; p < nPoints; p++) { 7800 PetscInt b = pnts[2 * p]; 7801 PetscInt bSecDof = 0, bOff; 7802 PetscInt cSecDof = 0; 7803 PetscSection indices_section; 7804 7805 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7806 if (!bSecDof) continue; 7807 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7808 indices_section = cSecDof > 0 ? cSec : section; 7809 if (numFields) { 7810 PetscInt fStart[32], fEnd[32]; 7811 7812 fStart[0] = 0; 7813 fEnd[0] = 0; 7814 for (PetscInt f = 0; f < numFields; f++) { 7815 PetscInt fDof = 0; 7816 7817 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7818 fStart[f + 1] = fStart[f] + fDof; 7819 fEnd[f + 1] = fStart[f + 1]; 7820 } 7821 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7822 // only apply permutations on one side 7823 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7824 for (PetscInt f = 0; f < numFields; f++) { 7825 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7826 } 7827 } else { 7828 PetscInt bEnd = 0; 7829 7830 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7831 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7832 7833 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7834 } 7835 } 7836 PetscFunctionReturn(PETSC_SUCCESS); 7837 } 7838 7839 PETSC_INTERN PetscErrorCode DMPlexAnchorsGetSubMatModification(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscInt offsets[], PetscScalar *outMat[]) 7840 { 7841 Mat cMat; 7842 PetscSection aSec, cSec; 7843 IS aIS; 7844 PetscInt aStart = -1, aEnd = -1; 7845 PetscInt sStart = -1, sEnd = -1; 7846 PetscInt cStart = -1, cEnd = -1; 7847 const PetscInt *anchors; 7848 PetscInt numFields, p; 7849 PetscInt newNumPoints = 0, newNumIndices = 0; 7850 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7851 PetscInt oldOffsets[32]; 7852 PetscInt newOffsets[32]; 7853 PetscInt oldOffsetsCopy[32]; 7854 PetscInt newOffsetsCopy[32]; 7855 PetscScalar *modMat = NULL; 7856 PetscBool anyConstrained = PETSC_FALSE; 7857 7858 PetscFunctionBegin; 7859 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7860 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7861 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7862 7863 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7864 /* if there are point-to-point constraints */ 7865 if (aSec) { 7866 PetscCall(PetscArrayzero(newOffsets, 32)); 7867 PetscCall(PetscArrayzero(oldOffsets, 32)); 7868 PetscCall(ISGetIndices(aIS, &anchors)); 7869 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7870 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7871 /* figure out how many points are going to be in the new element matrix 7872 * (we allow double counting, because it's all just going to be summed 7873 * into the global matrix anyway) */ 7874 for (p = 0; p < 2 * numPoints; p += 2) { 7875 PetscInt b = points[p]; 7876 PetscInt bDof = 0, bSecDof = 0; 7877 7878 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7879 if (!bSecDof) continue; 7880 7881 for (PetscInt f = 0; f < numFields; f++) { 7882 PetscInt fDof = 0; 7883 7884 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7885 oldOffsets[f + 1] += fDof; 7886 } 7887 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7888 if (bDof) { 7889 /* this point is constrained */ 7890 /* it is going to be replaced by its anchors */ 7891 PetscInt bOff, q; 7892 7893 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7894 for (q = 0; q < bDof; q++) { 7895 PetscInt a = anchors[bOff + q]; 7896 PetscInt aDof = 0; 7897 7898 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7899 if (aDof) { 7900 anyConstrained = PETSC_TRUE; 7901 newNumPoints += 1; 7902 } 7903 newNumIndices += aDof; 7904 for (PetscInt f = 0; f < numFields; ++f) { 7905 PetscInt fDof = 0; 7906 7907 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7908 newOffsets[f + 1] += fDof; 7909 } 7910 } 7911 } else { 7912 /* this point is not constrained */ 7913 newNumPoints++; 7914 newNumIndices += bSecDof; 7915 for (PetscInt f = 0; f < numFields; ++f) { 7916 PetscInt fDof; 7917 7918 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7919 newOffsets[f + 1] += fDof; 7920 } 7921 } 7922 } 7923 } 7924 if (!anyConstrained) { 7925 if (outNumPoints) *outNumPoints = 0; 7926 if (outNumIndices) *outNumIndices = 0; 7927 if (outPoints) *outPoints = NULL; 7928 if (outMat) *outMat = NULL; 7929 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7930 PetscFunctionReturn(PETSC_SUCCESS); 7931 } 7932 7933 if (outNumPoints) *outNumPoints = newNumPoints; 7934 if (outNumIndices) *outNumIndices = newNumIndices; 7935 7936 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7937 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7938 7939 if (!outPoints && !outMat) { 7940 if (offsets) { 7941 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7942 } 7943 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7944 PetscFunctionReturn(PETSC_SUCCESS); 7945 } 7946 7947 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7948 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7949 7950 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7951 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7952 7953 /* output arrays */ 7954 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7955 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7956 7957 // get the new Points 7958 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7959 PetscInt b = points[2 * p]; 7960 PetscInt bDof = 0, bSecDof = 0, bOff; 7961 7962 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7963 if (!bSecDof) continue; 7964 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7965 if (bDof) { 7966 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7967 for (PetscInt q = 0; q < bDof; q++) { 7968 PetscInt a = anchors[bOff + q], aDof = 0; 7969 7970 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7971 if (aDof) { 7972 newPoints[2 * newP] = a; 7973 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7974 newP++; 7975 } 7976 } 7977 } else { 7978 newPoints[2 * newP] = b; 7979 newPoints[2 * newP + 1] = points[2 * p + 1]; 7980 newP++; 7981 } 7982 } 7983 7984 if (outMat) { 7985 PetscScalar *tmpMat; 7986 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7987 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7988 7989 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7990 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7991 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7992 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7993 7994 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7995 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7996 7997 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7998 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7999 8000 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 8001 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 8002 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 8003 // for each field, insert the anchor modification into modMat 8004 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 8005 PetscInt fStart = oldOffsets[f]; 8006 PetscInt fNewStart = newOffsets[f]; 8007 for (PetscInt p = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 8008 PetscInt b = points[2 * p]; 8009 PetscInt bDof = 0, bSecDof = 0, bOff; 8010 8011 if (b >= sStart && b < sEnd) { 8012 if (numFields) { 8013 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 8014 } else { 8015 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 8016 } 8017 } 8018 if (!bSecDof) continue; 8019 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 8020 if (bDof) { 8021 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 8022 for (PetscInt q = 0; q < bDof; q++) { 8023 PetscInt a = anchors[bOff + q], aDof = 0; 8024 8025 if (a >= sStart && a < sEnd) { 8026 if (numFields) { 8027 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 8028 } else { 8029 PetscCall(PetscSectionGetDof(section, a, &aDof)); 8030 } 8031 } 8032 if (aDof) { 8033 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 8034 for (PetscInt d = 0; d < bSecDof; d++) { 8035 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 8036 } 8037 } 8038 oNew += aDof; 8039 } 8040 } else { 8041 // Insert the identity matrix in this block 8042 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 8043 oNew += bSecDof; 8044 } 8045 o += bSecDof; 8046 } 8047 } 8048 8049 *outMat = modMat; 8050 8051 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 8052 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 8053 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 8054 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 8055 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 8056 } 8057 PetscCall(ISRestoreIndices(aIS, &anchors)); 8058 8059 /* output */ 8060 if (outPoints) { 8061 *outPoints = newPoints; 8062 } else { 8063 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 8064 } 8065 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 8066 PetscFunctionReturn(PETSC_SUCCESS); 8067 } 8068 8069 PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat_Internal(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt numRows, PetscInt numCols, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyRight, PetscBool multiplyLeft) 8070 { 8071 PetscScalar *modMat = NULL; 8072 PetscInt newNumIndices = -1; 8073 8074 PetscFunctionBegin; 8075 /* If M is the matrix represented by values, get the matrix C such that we will add M * C (or, if multiplyLeft, C^T * M * C) into the global matrix. 8076 modMat is that matrix C */ 8077 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 8078 if (outNumIndices) *outNumIndices = newNumIndices; 8079 if (modMat) { 8080 const PetscScalar *newValues = values; 8081 8082 if (multiplyRight) { 8083 PetscScalar *newNewValues = NULL; 8084 PetscBLASInt M, N, K; 8085 PetscScalar a = 1.0, b = 0.0; 8086 8087 PetscCheck(numCols == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of columns: %" PetscInt_FMT ", expected %" PetscInt_FMT, numCols, numIndices); 8088 8089 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 8090 PetscCall(PetscBLASIntCast(numRows, &N)); 8091 PetscCall(PetscBLASIntCast(numIndices, &K)); 8092 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 8093 // row-major to column-major conversion, right multiplication becomes left multiplication 8094 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 8095 numCols = newNumIndices; 8096 newValues = newNewValues; 8097 } 8098 8099 if (multiplyLeft) { 8100 PetscScalar *newNewValues = NULL; 8101 PetscBLASInt M, N, K; 8102 PetscScalar a = 1.0, b = 0.0; 8103 8104 PetscCheck(numRows == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of rows: %" PetscInt_FMT ", expected %" PetscInt_FMT, numRows, numIndices); 8105 8106 PetscCall(PetscBLASIntCast(numCols, &M)); 8107 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 8108 PetscCall(PetscBLASIntCast(numIndices, &K)); 8109 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 8110 // row-major to column-major conversion, left multiplication becomes right multiplication 8111 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 8112 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 8113 newValues = newNewValues; 8114 } 8115 *outValues = (PetscScalar *)newValues; 8116 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 8117 } 8118 PetscFunctionReturn(PETSC_SUCCESS); 8119 } 8120 8121 PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft) 8122 { 8123 PetscFunctionBegin; 8124 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 8125 PetscFunctionReturn(PETSC_SUCCESS); 8126 } 8127 8128 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 8129 { 8130 /* Closure ordering */ 8131 PetscSection clSection; 8132 IS clPoints; 8133 const PetscInt *clp; 8134 PetscInt *points; 8135 PetscInt Ncl, Ni = 0; 8136 8137 PetscFunctionBeginHot; 8138 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8139 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 8140 PetscInt dof; 8141 8142 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8143 Ni += dof; 8144 } 8145 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8146 *closureSize = Ni; 8147 PetscFunctionReturn(PETSC_SUCCESS); 8148 } 8149 8150 static PetscErrorCode DMPlexGetClosureIndices_Internal(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numRows, PetscInt *numCols, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[], PetscBool multiplyRight, PetscBool multiplyLeft) 8151 { 8152 /* Closure ordering */ 8153 PetscSection clSection; 8154 IS clPoints; 8155 const PetscInt *clp; 8156 PetscInt *points; 8157 const PetscInt *clperm = NULL; 8158 /* Dof permutation and sign flips */ 8159 const PetscInt **perms[32] = {NULL}; 8160 const PetscScalar **flips[32] = {NULL}; 8161 PetscScalar *valCopy = NULL; 8162 /* Hanging node constraints */ 8163 PetscInt *pointsC = NULL; 8164 PetscScalar *valuesC = NULL; 8165 PetscInt NclC, NiC; 8166 8167 PetscInt *idx; 8168 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8169 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8170 PetscInt idxStart, idxEnd; 8171 PetscInt nRows, nCols; 8172 8173 PetscFunctionBeginHot; 8174 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8175 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8176 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8177 PetscAssertPointer(numRows, 6); 8178 PetscAssertPointer(numCols, 7); 8179 if (indices) PetscAssertPointer(indices, 8); 8180 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8181 if (values) PetscAssertPointer(values, 10); 8182 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8183 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8184 PetscCall(PetscArrayzero(offsets, 32)); 8185 /* 1) Get points in closure */ 8186 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8187 if (useClPerm) { 8188 PetscInt depth, clsize; 8189 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8190 for (clsize = 0, p = 0; p < Ncl; p++) { 8191 PetscInt dof; 8192 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8193 clsize += dof; 8194 } 8195 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8196 } 8197 /* 2) Get number of indices on these points and field offsets from section */ 8198 for (p = 0; p < Ncl * 2; p += 2) { 8199 PetscInt dof, fdof; 8200 8201 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8202 for (f = 0; f < Nf; ++f) { 8203 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8204 offsets[f + 1] += fdof; 8205 } 8206 Ni += dof; 8207 } 8208 if (*numRows == -1) *numRows = Ni; 8209 if (*numCols == -1) *numCols = Ni; 8210 nRows = *numRows; 8211 nCols = *numCols; 8212 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8213 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8214 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8215 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8216 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8217 for (f = 0; f < PetscMax(1, Nf); ++f) { 8218 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8219 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8220 /* may need to apply sign changes to the element matrix */ 8221 if (values && flips[f]) { 8222 PetscInt foffset = offsets[f]; 8223 8224 for (p = 0; p < Ncl; ++p) { 8225 PetscInt pnt = points[2 * p], fdof; 8226 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8227 8228 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8229 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8230 if (flip) { 8231 PetscInt i, j, k; 8232 8233 if (!valCopy) { 8234 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8235 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8236 *values = valCopy; 8237 } 8238 for (i = 0; i < fdof; ++i) { 8239 PetscScalar fval = flip[i]; 8240 8241 if (multiplyRight) { 8242 for (k = 0; k < nRows; ++k) valCopy[Ni * k + (foffset + i)] *= fval; 8243 } 8244 if (multiplyLeft) { 8245 for (k = 0; k < nCols; ++k) valCopy[nCols * (foffset + i) + k] *= fval; 8246 } 8247 } 8248 } 8249 foffset += fdof; 8250 } 8251 } 8252 } 8253 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8254 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8255 if (NclC) { 8256 if (multiplyRight) *numCols = NiC; 8257 if (multiplyLeft) *numRows = NiC; 8258 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8259 for (f = 0; f < PetscMax(1, Nf); ++f) { 8260 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8261 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8262 } 8263 for (f = 0; f < PetscMax(1, Nf); ++f) { 8264 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8265 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8266 } 8267 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8268 Ncl = NclC; 8269 Ni = NiC; 8270 points = pointsC; 8271 if (values) *values = valuesC; 8272 } 8273 /* 5) Calculate indices */ 8274 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8275 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8276 if (Nf) { 8277 PetscInt idxOff; 8278 PetscBool useFieldOffsets; 8279 8280 if (outOffsets) { 8281 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8282 } 8283 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8284 if (useFieldOffsets) { 8285 for (p = 0; p < Ncl; ++p) { 8286 const PetscInt pnt = points[p * 2]; 8287 8288 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8289 } 8290 } else { 8291 for (p = 0; p < Ncl; ++p) { 8292 const PetscInt pnt = points[p * 2]; 8293 8294 if (pnt < idxStart || pnt >= idxEnd) continue; 8295 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8296 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8297 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8298 * global section. */ 8299 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8300 } 8301 } 8302 } else { 8303 PetscInt off = 0, idxOff; 8304 8305 for (p = 0; p < Ncl; ++p) { 8306 const PetscInt pnt = points[p * 2]; 8307 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8308 8309 if (pnt < idxStart || pnt >= idxEnd) continue; 8310 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8311 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8312 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8313 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8314 } 8315 } 8316 /* 6) Cleanup */ 8317 for (f = 0; f < PetscMax(1, Nf); ++f) { 8318 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8319 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8320 } 8321 if (NclC) { 8322 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8323 } else { 8324 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8325 } 8326 8327 if (indices) *indices = idx; 8328 PetscFunctionReturn(PETSC_SUCCESS); 8329 } 8330 8331 /*@C 8332 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8333 8334 Not collective 8335 8336 Input Parameters: 8337 + dm - The `DM` 8338 . section - The `PetscSection` describing the points (a local section) 8339 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8340 . point - The point defining the closure 8341 - useClPerm - Use the closure point permutation if available 8342 8343 Output Parameters: 8344 + numIndices - The number of dof indices in the closure of point with the input sections 8345 . indices - The dof indices 8346 . outOffsets - Array, of length the number of fields plus 1, to write the field offsets into, or `NULL` 8347 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8348 8349 Level: advanced 8350 8351 Notes: 8352 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8353 8354 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8355 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8356 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8357 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8358 indices (with the above semantics) are implied. 8359 8360 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8361 `PetscSection`, `DMGetGlobalSection()` 8362 @*/ 8363 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8364 { 8365 PetscInt numRows = -1, numCols = -1; 8366 8367 PetscFunctionBeginHot; 8368 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8369 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8370 *numIndices = numRows; 8371 PetscFunctionReturn(PETSC_SUCCESS); 8372 } 8373 8374 /*@C 8375 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8376 8377 Not collective 8378 8379 Input Parameters: 8380 + dm - The `DM` 8381 . section - The `PetscSection` describing the points (a local section) 8382 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8383 . point - The point defining the closure 8384 - useClPerm - Use the closure point permutation if available 8385 8386 Output Parameters: 8387 + numIndices - The number of dof indices in the closure of point with the input sections 8388 . indices - The dof indices 8389 . outOffsets - Array to write the field offsets into, or `NULL` 8390 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8391 8392 Level: advanced 8393 8394 Notes: 8395 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8396 8397 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8398 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8399 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8400 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8401 indices (with the above semantics) are implied. 8402 8403 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8404 @*/ 8405 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8406 { 8407 PetscFunctionBegin; 8408 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8409 PetscAssertPointer(indices, 7); 8410 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8411 PetscFunctionReturn(PETSC_SUCCESS); 8412 } 8413 8414 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8415 { 8416 DM_Plex *mesh = (DM_Plex *)dm->data; 8417 PetscInt *indices; 8418 PetscInt numIndices; 8419 const PetscScalar *valuesOrig = values; 8420 PetscErrorCode ierr; 8421 8422 PetscFunctionBegin; 8423 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8424 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8425 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8426 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8427 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8428 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8429 8430 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8431 8432 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8433 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8434 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8435 if (ierr) { 8436 PetscMPIInt rank; 8437 8438 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8439 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8440 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8441 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8442 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8443 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8444 } 8445 if (mesh->printFEM > 1) { 8446 PetscInt i; 8447 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8448 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8449 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8450 } 8451 8452 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8453 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8454 PetscFunctionReturn(PETSC_SUCCESS); 8455 } 8456 8457 /*@C 8458 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8459 8460 Not collective 8461 8462 Input Parameters: 8463 + dm - The `DM` 8464 . section - The section describing the layout in `v`, or `NULL` to use the default section 8465 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8466 . A - The matrix 8467 . point - The point in the `DM` 8468 . values - The array of values 8469 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8470 8471 Level: intermediate 8472 8473 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8474 @*/ 8475 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8476 { 8477 PetscFunctionBegin; 8478 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8479 PetscFunctionReturn(PETSC_SUCCESS); 8480 } 8481 8482 /*@C 8483 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8484 8485 Not collective 8486 8487 Input Parameters: 8488 + dmRow - The `DM` for the row fields 8489 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8490 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8491 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8492 . dmCol - The `DM` for the column fields 8493 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8494 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8495 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8496 . A - The matrix 8497 . point - The point in the `DM` 8498 . values - The array of values 8499 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8500 8501 Level: intermediate 8502 8503 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8504 @*/ 8505 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) 8506 { 8507 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8508 PetscInt *indicesRow, *indicesCol; 8509 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8510 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8511 8512 PetscErrorCode ierr; 8513 8514 PetscFunctionBegin; 8515 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8516 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8517 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8518 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8519 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8520 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8521 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8522 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8523 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8524 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8525 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8526 8527 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8528 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8529 valuesV1 = valuesV0; 8530 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8531 valuesV2 = valuesV1; 8532 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8533 8534 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8535 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8536 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8537 if (ierr) { 8538 PetscMPIInt rank; 8539 8540 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8541 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8542 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8543 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8544 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8545 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8546 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8547 } 8548 8549 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8550 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8551 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8552 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8553 PetscFunctionReturn(PETSC_SUCCESS); 8554 } 8555 8556 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8557 { 8558 DM_Plex *mesh = (DM_Plex *)dmf->data; 8559 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8560 PetscInt *cpoints = NULL; 8561 PetscInt *findices, *cindices; 8562 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8563 PetscInt foffsets[32], coffsets[32]; 8564 DMPolytopeType ct; 8565 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8566 PetscErrorCode ierr; 8567 8568 PetscFunctionBegin; 8569 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8570 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8571 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8572 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8573 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8574 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8575 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8576 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8577 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8578 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8579 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8580 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8581 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8582 PetscCall(PetscArrayzero(foffsets, 32)); 8583 PetscCall(PetscArrayzero(coffsets, 32)); 8584 /* Column indices */ 8585 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8586 maxFPoints = numCPoints; 8587 /* Compress out points not in the section */ 8588 /* TODO: Squeeze out points with 0 dof as well */ 8589 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8590 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8591 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8592 cpoints[q * 2] = cpoints[p]; 8593 cpoints[q * 2 + 1] = cpoints[p + 1]; 8594 ++q; 8595 } 8596 } 8597 numCPoints = q; 8598 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8599 PetscInt fdof; 8600 8601 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8602 if (!dof) continue; 8603 for (f = 0; f < numFields; ++f) { 8604 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8605 coffsets[f + 1] += fdof; 8606 } 8607 numCIndices += dof; 8608 } 8609 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8610 /* Row indices */ 8611 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8612 { 8613 DMPlexTransform tr; 8614 DMPolytopeType *rct; 8615 PetscInt *rsize, *rcone, *rornt, Nt; 8616 8617 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8618 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8619 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8620 numSubcells = rsize[Nt - 1]; 8621 PetscCall(DMPlexTransformDestroy(&tr)); 8622 } 8623 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8624 for (r = 0, q = 0; r < numSubcells; ++r) { 8625 /* TODO Map from coarse to fine cells */ 8626 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8627 /* Compress out points not in the section */ 8628 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8629 for (p = 0; p < numFPoints * 2; p += 2) { 8630 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8631 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8632 if (!dof) continue; 8633 for (s = 0; s < q; ++s) 8634 if (fpoints[p] == ftotpoints[s * 2]) break; 8635 if (s < q) continue; 8636 ftotpoints[q * 2] = fpoints[p]; 8637 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8638 ++q; 8639 } 8640 } 8641 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8642 } 8643 numFPoints = q; 8644 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8645 PetscInt fdof; 8646 8647 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8648 if (!dof) continue; 8649 for (f = 0; f < numFields; ++f) { 8650 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8651 foffsets[f + 1] += fdof; 8652 } 8653 numFIndices += dof; 8654 } 8655 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8656 8657 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8658 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8659 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8660 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8661 if (numFields) { 8662 const PetscInt **permsF[32] = {NULL}; 8663 const PetscInt **permsC[32] = {NULL}; 8664 8665 for (f = 0; f < numFields; f++) { 8666 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8667 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8668 } 8669 for (p = 0; p < numFPoints; p++) { 8670 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8671 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8672 } 8673 for (p = 0; p < numCPoints; p++) { 8674 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8675 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8676 } 8677 for (f = 0; f < numFields; f++) { 8678 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8679 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8680 } 8681 } else { 8682 const PetscInt **permsF = NULL; 8683 const PetscInt **permsC = NULL; 8684 8685 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8686 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8687 for (p = 0, off = 0; p < numFPoints; p++) { 8688 const PetscInt *perm = permsF ? permsF[p] : NULL; 8689 8690 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8691 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8692 } 8693 for (p = 0, off = 0; p < numCPoints; p++) { 8694 const PetscInt *perm = permsC ? permsC[p] : NULL; 8695 8696 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8697 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8698 } 8699 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8700 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8701 } 8702 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8703 /* TODO: flips */ 8704 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8705 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8706 if (ierr) { 8707 PetscMPIInt rank; 8708 8709 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8710 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8711 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8712 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8713 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8714 } 8715 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8716 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8717 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8718 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8719 PetscFunctionReturn(PETSC_SUCCESS); 8720 } 8721 8722 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8723 { 8724 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8725 PetscInt *cpoints = NULL; 8726 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8727 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8728 DMPolytopeType ct; 8729 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8730 8731 PetscFunctionBegin; 8732 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8733 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8734 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8735 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8736 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8737 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8738 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8739 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8740 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8741 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8742 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8743 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8744 /* Column indices */ 8745 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8746 maxFPoints = numCPoints; 8747 /* Compress out points not in the section */ 8748 /* TODO: Squeeze out points with 0 dof as well */ 8749 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8750 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8751 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8752 cpoints[q * 2] = cpoints[p]; 8753 cpoints[q * 2 + 1] = cpoints[p + 1]; 8754 ++q; 8755 } 8756 } 8757 numCPoints = q; 8758 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8759 PetscInt fdof; 8760 8761 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8762 if (!dof) continue; 8763 for (f = 0; f < numFields; ++f) { 8764 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8765 coffsets[f + 1] += fdof; 8766 } 8767 numCIndices += dof; 8768 } 8769 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8770 /* Row indices */ 8771 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8772 { 8773 DMPlexTransform tr; 8774 DMPolytopeType *rct; 8775 PetscInt *rsize, *rcone, *rornt, Nt; 8776 8777 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8778 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8779 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8780 numSubcells = rsize[Nt - 1]; 8781 PetscCall(DMPlexTransformDestroy(&tr)); 8782 } 8783 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8784 for (r = 0, q = 0; r < numSubcells; ++r) { 8785 /* TODO Map from coarse to fine cells */ 8786 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8787 /* Compress out points not in the section */ 8788 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8789 for (p = 0; p < numFPoints * 2; p += 2) { 8790 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8791 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8792 if (!dof) continue; 8793 for (s = 0; s < q; ++s) 8794 if (fpoints[p] == ftotpoints[s * 2]) break; 8795 if (s < q) continue; 8796 ftotpoints[q * 2] = fpoints[p]; 8797 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8798 ++q; 8799 } 8800 } 8801 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8802 } 8803 numFPoints = q; 8804 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8805 PetscInt fdof; 8806 8807 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8808 if (!dof) continue; 8809 for (f = 0; f < numFields; ++f) { 8810 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8811 foffsets[f + 1] += fdof; 8812 } 8813 numFIndices += dof; 8814 } 8815 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8816 8817 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8818 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8819 if (numFields) { 8820 const PetscInt **permsF[32] = {NULL}; 8821 const PetscInt **permsC[32] = {NULL}; 8822 8823 for (f = 0; f < numFields; f++) { 8824 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8825 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8826 } 8827 for (p = 0; p < numFPoints; p++) { 8828 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8829 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8830 } 8831 for (p = 0; p < numCPoints; p++) { 8832 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8833 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8834 } 8835 for (f = 0; f < numFields; f++) { 8836 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8837 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8838 } 8839 } else { 8840 const PetscInt **permsF = NULL; 8841 const PetscInt **permsC = NULL; 8842 8843 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8844 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8845 for (p = 0, off = 0; p < numFPoints; p++) { 8846 const PetscInt *perm = permsF ? permsF[p] : NULL; 8847 8848 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8849 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8850 } 8851 for (p = 0, off = 0; p < numCPoints; p++) { 8852 const PetscInt *perm = permsC ? permsC[p] : NULL; 8853 8854 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8855 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8856 } 8857 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8858 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8859 } 8860 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8861 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8862 PetscFunctionReturn(PETSC_SUCCESS); 8863 } 8864 8865 /*@ 8866 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8867 8868 Input Parameter: 8869 . dm - The `DMPLEX` object 8870 8871 Output Parameter: 8872 . cellHeight - The height of a cell 8873 8874 Level: developer 8875 8876 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8877 @*/ 8878 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8879 { 8880 DM_Plex *mesh = (DM_Plex *)dm->data; 8881 8882 PetscFunctionBegin; 8883 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8884 PetscAssertPointer(cellHeight, 2); 8885 *cellHeight = mesh->vtkCellHeight; 8886 PetscFunctionReturn(PETSC_SUCCESS); 8887 } 8888 8889 /*@ 8890 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8891 8892 Input Parameters: 8893 + dm - The `DMPLEX` object 8894 - cellHeight - The height of a cell 8895 8896 Level: developer 8897 8898 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8899 @*/ 8900 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8901 { 8902 DM_Plex *mesh = (DM_Plex *)dm->data; 8903 8904 PetscFunctionBegin; 8905 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8906 mesh->vtkCellHeight = cellHeight; 8907 PetscFunctionReturn(PETSC_SUCCESS); 8908 } 8909 8910 /*@ 8911 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8912 8913 Input Parameters: 8914 + dm - The `DMPLEX` object 8915 - ct - The `DMPolytopeType` of the cell 8916 8917 Output Parameters: 8918 + start - The first cell of this type, or `NULL` 8919 - end - The upper bound on this celltype, or `NULL` 8920 8921 Level: advanced 8922 8923 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8924 @*/ 8925 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end) 8926 { 8927 DM_Plex *mesh = (DM_Plex *)dm->data; 8928 DMLabel label; 8929 PetscInt pStart, pEnd; 8930 8931 PetscFunctionBegin; 8932 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8933 if (start) { 8934 PetscAssertPointer(start, 3); 8935 *start = 0; 8936 } 8937 if (end) { 8938 PetscAssertPointer(end, 4); 8939 *end = 0; 8940 } 8941 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8942 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8943 if (mesh->tr) { 8944 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8945 } else { 8946 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8947 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8948 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8949 } 8950 PetscFunctionReturn(PETSC_SUCCESS); 8951 } 8952 8953 /*@ 8954 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8955 8956 Input Parameters: 8957 + dm - The `DMPLEX` object 8958 - depth - The depth for the given point stratum 8959 8960 Output Parameter: 8961 . gsize - The global number of points in the stratum 8962 8963 Level: advanced 8964 8965 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8966 @*/ 8967 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8968 { 8969 PetscSF sf; 8970 const PetscInt *leaves; 8971 PetscInt Nl, loc, start, end, lsize = 0; 8972 8973 PetscFunctionBegin; 8974 PetscCall(DMGetPointSF(dm, &sf)); 8975 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8976 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8977 for (PetscInt p = start; p < end; ++p) { 8978 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8979 if (loc < 0) ++lsize; 8980 } 8981 PetscCallMPI(MPIU_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8982 PetscFunctionReturn(PETSC_SUCCESS); 8983 } 8984 8985 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8986 { 8987 PetscSection section, globalSection; 8988 PetscInt *numbers, p; 8989 8990 PetscFunctionBegin; 8991 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8992 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8993 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8994 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8995 PetscCall(PetscSectionSetUp(section)); 8996 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8997 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8998 for (p = pStart; p < pEnd; ++p) { 8999 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 9000 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 9001 else numbers[p - pStart] += shift; 9002 } 9003 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 9004 if (globalSize) { 9005 PetscLayout layout; 9006 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 9007 PetscCall(PetscLayoutGetSize(layout, globalSize)); 9008 PetscCall(PetscLayoutDestroy(&layout)); 9009 } 9010 PetscCall(PetscSectionDestroy(§ion)); 9011 PetscCall(PetscSectionDestroy(&globalSection)); 9012 PetscFunctionReturn(PETSC_SUCCESS); 9013 } 9014 9015 /*@ 9016 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 9017 9018 Input Parameters: 9019 + dm - The `DMPLEX` object 9020 - includeAll - Whether to include all cells, or just the simplex and box cells 9021 9022 Output Parameter: 9023 . globalCellNumbers - Global cell numbers for all cells on this process 9024 9025 Level: developer 9026 9027 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 9028 @*/ 9029 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 9030 { 9031 PetscInt cellHeight, cStart, cEnd; 9032 9033 PetscFunctionBegin; 9034 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9035 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9036 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 9037 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 9038 PetscFunctionReturn(PETSC_SUCCESS); 9039 } 9040 9041 /*@ 9042 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 9043 9044 Input Parameter: 9045 . dm - The `DMPLEX` object 9046 9047 Output Parameter: 9048 . globalCellNumbers - Global cell numbers for all cells on this process 9049 9050 Level: developer 9051 9052 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 9053 @*/ 9054 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 9055 { 9056 DM_Plex *mesh = (DM_Plex *)dm->data; 9057 9058 PetscFunctionBegin; 9059 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9060 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 9061 *globalCellNumbers = mesh->globalCellNumbers; 9062 PetscFunctionReturn(PETSC_SUCCESS); 9063 } 9064 9065 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 9066 { 9067 PetscInt vStart, vEnd; 9068 9069 PetscFunctionBegin; 9070 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9071 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9072 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 9073 PetscFunctionReturn(PETSC_SUCCESS); 9074 } 9075 9076 /*@ 9077 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 9078 9079 Input Parameter: 9080 . dm - The `DMPLEX` object 9081 9082 Output Parameter: 9083 . globalVertexNumbers - Global vertex numbers for all vertices on this process 9084 9085 Level: developer 9086 9087 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9088 @*/ 9089 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 9090 { 9091 DM_Plex *mesh = (DM_Plex *)dm->data; 9092 9093 PetscFunctionBegin; 9094 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9095 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 9096 *globalVertexNumbers = mesh->globalVertexNumbers; 9097 PetscFunctionReturn(PETSC_SUCCESS); 9098 } 9099 9100 /*@ 9101 DMPlexCreatePointNumbering - Create a global numbering for all points. 9102 9103 Collective 9104 9105 Input Parameter: 9106 . dm - The `DMPLEX` object 9107 9108 Output Parameter: 9109 . globalPointNumbers - Global numbers for all points on this process 9110 9111 Level: developer 9112 9113 Notes: 9114 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 9115 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 9116 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 9117 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 9118 9119 The partitioned mesh is 9120 ``` 9121 (2)--0--(3)--1--(4) (1)--0--(2) 9122 ``` 9123 and its global numbering is 9124 ``` 9125 (3)--0--(4)--1--(5)--2--(6) 9126 ``` 9127 Then the global numbering is provided as 9128 ``` 9129 [0] Number of indices in set 5 9130 [0] 0 0 9131 [0] 1 1 9132 [0] 2 3 9133 [0] 3 4 9134 [0] 4 -6 9135 [1] Number of indices in set 3 9136 [1] 0 2 9137 [1] 1 5 9138 [1] 2 6 9139 ``` 9140 9141 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9142 @*/ 9143 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 9144 { 9145 IS nums[4]; 9146 PetscInt depths[4], gdepths[4], starts[4]; 9147 PetscInt depth, d, shift = 0; 9148 PetscBool empty = PETSC_FALSE; 9149 9150 PetscFunctionBegin; 9151 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9152 PetscCall(DMPlexGetDepth(dm, &depth)); 9153 // For unstratified meshes use dim instead of depth 9154 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9155 // If any stratum is empty, we must mark all empty 9156 for (d = 0; d <= depth; ++d) { 9157 PetscInt end; 9158 9159 depths[d] = depth - d; 9160 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9161 if (!(starts[d] - end)) empty = PETSC_TRUE; 9162 } 9163 if (empty) 9164 for (d = 0; d <= depth; ++d) { 9165 depths[d] = -1; 9166 starts[d] = -1; 9167 } 9168 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9169 PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9170 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]); 9171 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9172 for (d = 0; d <= depth; ++d) { 9173 PetscInt pStart, pEnd, gsize; 9174 9175 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9176 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9177 shift += gsize; 9178 } 9179 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9180 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9181 PetscFunctionReturn(PETSC_SUCCESS); 9182 } 9183 9184 /*@ 9185 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9186 9187 Collective 9188 9189 Input Parameter: 9190 . dm - The `DMPLEX` object 9191 9192 Output Parameter: 9193 . globalEdgeNumbers - Global numbers for all edges on this process 9194 9195 Level: developer 9196 9197 Notes: 9198 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). In the IS, owned edges will have their non-negative value while edges owned by different ranks will be involuted -(idx+1). 9199 9200 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9201 @*/ 9202 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9203 { 9204 PetscSF sf; 9205 PetscInt eStart, eEnd; 9206 9207 PetscFunctionBegin; 9208 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9209 PetscCall(DMGetPointSF(dm, &sf)); 9210 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9211 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9212 PetscFunctionReturn(PETSC_SUCCESS); 9213 } 9214 9215 /*@ 9216 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9217 9218 Input Parameter: 9219 . dm - The `DMPLEX` object 9220 9221 Output Parameter: 9222 . ranks - The rank field 9223 9224 Options Database Key: 9225 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9226 9227 Level: intermediate 9228 9229 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9230 @*/ 9231 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9232 { 9233 DM rdm; 9234 PetscFE fe; 9235 PetscScalar *r; 9236 PetscMPIInt rank; 9237 DMPolytopeType ct; 9238 PetscInt dim, cStart, cEnd, c; 9239 PetscBool simplex; 9240 9241 PetscFunctionBeginUser; 9242 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9243 PetscAssertPointer(ranks, 2); 9244 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9245 PetscCall(DMClone(dm, &rdm)); 9246 PetscCall(DMGetDimension(rdm, &dim)); 9247 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9248 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9249 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9250 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9251 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9252 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9253 PetscCall(PetscFEDestroy(&fe)); 9254 PetscCall(DMCreateDS(rdm)); 9255 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9256 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9257 PetscCall(VecGetArray(*ranks, &r)); 9258 for (c = cStart; c < cEnd; ++c) { 9259 PetscScalar *lr; 9260 9261 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9262 if (lr) *lr = rank; 9263 } 9264 PetscCall(VecRestoreArray(*ranks, &r)); 9265 PetscCall(DMDestroy(&rdm)); 9266 PetscFunctionReturn(PETSC_SUCCESS); 9267 } 9268 9269 /*@ 9270 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9271 9272 Input Parameters: 9273 + dm - The `DMPLEX` 9274 - label - The `DMLabel` 9275 9276 Output Parameter: 9277 . val - The label value field 9278 9279 Options Database Key: 9280 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9281 9282 Level: intermediate 9283 9284 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9285 @*/ 9286 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9287 { 9288 DM rdm, plex; 9289 Vec lval; 9290 PetscSection section; 9291 PetscFE fe; 9292 PetscScalar *v; 9293 PetscInt dim, pStart, pEnd, p, cStart; 9294 DMPolytopeType ct; 9295 char name[PETSC_MAX_PATH_LEN]; 9296 const char *lname, *prefix; 9297 9298 PetscFunctionBeginUser; 9299 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9300 PetscAssertPointer(label, 2); 9301 PetscAssertPointer(val, 3); 9302 PetscCall(DMClone(dm, &rdm)); 9303 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9304 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9305 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9306 PetscCall(DMDestroy(&plex)); 9307 PetscCall(DMGetDimension(rdm, &dim)); 9308 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9309 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9310 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9311 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9312 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9313 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9314 PetscCall(PetscFEDestroy(&fe)); 9315 PetscCall(DMCreateDS(rdm)); 9316 PetscCall(DMCreateGlobalVector(rdm, val)); 9317 PetscCall(DMCreateLocalVector(rdm, &lval)); 9318 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9319 PetscCall(DMGetLocalSection(rdm, §ion)); 9320 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9321 PetscCall(VecGetArray(lval, &v)); 9322 for (p = pStart; p < pEnd; ++p) { 9323 PetscInt cval, dof, off; 9324 9325 PetscCall(PetscSectionGetDof(section, p, &dof)); 9326 if (!dof) continue; 9327 PetscCall(DMLabelGetValue(label, p, &cval)); 9328 PetscCall(PetscSectionGetOffset(section, p, &off)); 9329 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9330 } 9331 PetscCall(VecRestoreArray(lval, &v)); 9332 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9333 PetscCall(VecDestroy(&lval)); 9334 PetscCall(DMDestroy(&rdm)); 9335 PetscFunctionReturn(PETSC_SUCCESS); 9336 } 9337 9338 /*@ 9339 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9340 9341 Input Parameter: 9342 . dm - The `DMPLEX` object 9343 9344 Level: developer 9345 9346 Notes: 9347 This is a useful diagnostic when creating meshes programmatically. 9348 9349 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9350 9351 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9352 @*/ 9353 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9354 { 9355 PetscSection coneSection, supportSection; 9356 const PetscInt *cone, *support; 9357 PetscInt coneSize, c, supportSize, s; 9358 PetscInt pStart, pEnd, p, pp, csize, ssize; 9359 PetscBool storagecheck = PETSC_TRUE; 9360 9361 PetscFunctionBegin; 9362 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9363 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9364 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9365 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9366 /* Check that point p is found in the support of its cone points, and vice versa */ 9367 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9368 for (p = pStart; p < pEnd; ++p) { 9369 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9370 PetscCall(DMPlexGetCone(dm, p, &cone)); 9371 for (c = 0; c < coneSize; ++c) { 9372 PetscBool dup = PETSC_FALSE; 9373 PetscInt d; 9374 for (d = c - 1; d >= 0; --d) { 9375 if (cone[c] == cone[d]) { 9376 dup = PETSC_TRUE; 9377 break; 9378 } 9379 } 9380 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9381 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9382 for (s = 0; s < supportSize; ++s) { 9383 if (support[s] == p) break; 9384 } 9385 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9386 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9387 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9388 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9389 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9390 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9391 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9392 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]); 9393 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9394 } 9395 } 9396 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9397 if (p != pp) { 9398 storagecheck = PETSC_FALSE; 9399 continue; 9400 } 9401 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9402 PetscCall(DMPlexGetSupport(dm, p, &support)); 9403 for (s = 0; s < supportSize; ++s) { 9404 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9405 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9406 for (c = 0; c < coneSize; ++c) { 9407 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9408 if (cone[c] != pp) { 9409 c = 0; 9410 break; 9411 } 9412 if (cone[c] == p) break; 9413 } 9414 if (c >= coneSize) { 9415 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9416 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9417 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9418 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9419 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9420 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9421 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9422 } 9423 } 9424 } 9425 if (storagecheck) { 9426 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9427 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9428 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9429 } 9430 PetscFunctionReturn(PETSC_SUCCESS); 9431 } 9432 9433 /* 9434 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. 9435 */ 9436 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9437 { 9438 DMPolytopeType cct; 9439 PetscInt ptpoints[4]; 9440 const PetscInt *cone, *ccone, *ptcone; 9441 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9442 9443 PetscFunctionBegin; 9444 *unsplit = 0; 9445 switch (ct) { 9446 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9447 ptpoints[npt++] = c; 9448 break; 9449 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9450 PetscCall(DMPlexGetCone(dm, c, &cone)); 9451 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9452 for (cp = 0; cp < coneSize; ++cp) { 9453 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9454 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9455 } 9456 break; 9457 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9458 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9459 PetscCall(DMPlexGetCone(dm, c, &cone)); 9460 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9461 for (cp = 0; cp < coneSize; ++cp) { 9462 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9463 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9464 for (ccp = 0; ccp < cconeSize; ++ccp) { 9465 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9466 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9467 PetscInt p; 9468 for (p = 0; p < npt; ++p) 9469 if (ptpoints[p] == ccone[ccp]) break; 9470 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9471 } 9472 } 9473 } 9474 break; 9475 default: 9476 break; 9477 } 9478 for (pt = 0; pt < npt; ++pt) { 9479 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9480 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9481 } 9482 PetscFunctionReturn(PETSC_SUCCESS); 9483 } 9484 9485 /*@ 9486 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9487 9488 Input Parameters: 9489 + dm - The `DMPLEX` object 9490 - cellHeight - Normally 0 9491 9492 Level: developer 9493 9494 Notes: 9495 This is a useful diagnostic when creating meshes programmatically. 9496 Currently applicable only to homogeneous simplex or tensor meshes. 9497 9498 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9499 9500 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9501 @*/ 9502 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9503 { 9504 DMPlexInterpolatedFlag interp; 9505 DMPolytopeType ct; 9506 PetscInt vStart, vEnd, cStart, cEnd, c; 9507 9508 PetscFunctionBegin; 9509 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9510 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9511 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9512 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9513 for (c = cStart; c < cEnd; ++c) { 9514 PetscInt *closure = NULL; 9515 PetscInt coneSize, closureSize, cl, Nv = 0; 9516 9517 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9518 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9519 if (interp == DMPLEX_INTERPOLATED_FULL) { 9520 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9521 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)); 9522 } 9523 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9524 for (cl = 0; cl < closureSize * 2; cl += 2) { 9525 const PetscInt p = closure[cl]; 9526 if ((p >= vStart) && (p < vEnd)) ++Nv; 9527 } 9528 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9529 /* Special Case: Tensor faces with identified vertices */ 9530 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9531 PetscInt unsplit; 9532 9533 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9534 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9535 } 9536 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)); 9537 } 9538 PetscFunctionReturn(PETSC_SUCCESS); 9539 } 9540 9541 /*@ 9542 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9543 9544 Collective 9545 9546 Input Parameters: 9547 + dm - The `DMPLEX` object 9548 - cellHeight - Normally 0 9549 9550 Level: developer 9551 9552 Notes: 9553 This is a useful diagnostic when creating meshes programmatically. 9554 This routine is only relevant for meshes that are fully interpolated across all ranks. 9555 It will error out if a partially interpolated mesh is given on some rank. 9556 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9557 9558 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9559 9560 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9561 @*/ 9562 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9563 { 9564 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9565 DMPlexInterpolatedFlag interpEnum; 9566 9567 PetscFunctionBegin; 9568 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9569 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9570 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9571 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9572 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9573 PetscFunctionReturn(PETSC_SUCCESS); 9574 } 9575 9576 PetscCall(DMGetDimension(dm, &dim)); 9577 PetscCall(DMPlexGetDepth(dm, &depth)); 9578 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9579 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9580 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9581 for (c = cStart; c < cEnd; ++c) { 9582 const PetscInt *cone, *ornt, *faceSizes, *faces; 9583 const DMPolytopeType *faceTypes; 9584 DMPolytopeType ct; 9585 PetscInt numFaces, coneSize, f; 9586 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9587 9588 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9589 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9590 if (unsplit) continue; 9591 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9592 PetscCall(DMPlexGetCone(dm, c, &cone)); 9593 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9594 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9595 for (cl = 0; cl < closureSize * 2; cl += 2) { 9596 const PetscInt p = closure[cl]; 9597 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9598 } 9599 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9600 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); 9601 for (f = 0; f < numFaces; ++f) { 9602 DMPolytopeType fct; 9603 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9604 9605 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9606 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9607 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9608 const PetscInt p = fclosure[cl]; 9609 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9610 } 9611 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]); 9612 for (v = 0; v < fnumCorners; ++v) { 9613 if (fclosure[v] != faces[fOff + v]) { 9614 PetscInt v1; 9615 9616 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9617 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9618 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9619 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9620 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9621 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]); 9622 } 9623 } 9624 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9625 fOff += faceSizes[f]; 9626 } 9627 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9628 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9629 } 9630 } 9631 PetscFunctionReturn(PETSC_SUCCESS); 9632 } 9633 9634 /*@ 9635 DMPlexCheckGeometry - Check the geometry of mesh cells 9636 9637 Input Parameter: 9638 . dm - The `DMPLEX` object 9639 9640 Level: developer 9641 9642 Notes: 9643 This is a useful diagnostic when creating meshes programmatically. 9644 9645 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9646 9647 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9648 @*/ 9649 PetscErrorCode DMPlexCheckGeometry(DM dm) 9650 { 9651 Vec coordinates; 9652 PetscReal detJ, J[9], refVol = 1.0; 9653 PetscReal vol; 9654 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9655 9656 PetscFunctionBegin; 9657 PetscCall(DMGetDimension(dm, &dim)); 9658 PetscCall(DMGetCoordinateDim(dm, &dE)); 9659 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9660 PetscCall(DMPlexGetDepth(dm, &depth)); 9661 for (d = 0; d < dim; ++d) refVol *= 2.0; 9662 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9663 /* Make sure local coordinates are created, because that step is collective */ 9664 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9665 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9666 for (c = cStart; c < cEnd; ++c) { 9667 DMPolytopeType ct; 9668 PetscInt unsplit; 9669 PetscBool ignoreZeroVol = PETSC_FALSE; 9670 9671 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9672 switch (ct) { 9673 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9674 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9675 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9676 ignoreZeroVol = PETSC_TRUE; 9677 break; 9678 default: 9679 break; 9680 } 9681 switch (ct) { 9682 case DM_POLYTOPE_TRI_PRISM: 9683 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9684 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9685 case DM_POLYTOPE_PYRAMID: 9686 continue; 9687 default: 9688 break; 9689 } 9690 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9691 if (unsplit) continue; 9692 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9693 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); 9694 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9695 /* This should work with periodicity since DG coordinates should be used */ 9696 if (depth > 1) { 9697 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9698 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); 9699 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9700 } 9701 } 9702 PetscFunctionReturn(PETSC_SUCCESS); 9703 } 9704 9705 /*@ 9706 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9707 9708 Collective 9709 9710 Input Parameters: 9711 + dm - The `DMPLEX` object 9712 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9713 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9714 9715 Level: developer 9716 9717 Notes: 9718 This is mainly intended for debugging/testing purposes. 9719 9720 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9721 9722 Extra roots can come from periodic cuts, where additional points appear on the boundary 9723 9724 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9725 @*/ 9726 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9727 { 9728 PetscInt l, nleaves, nroots, overlap; 9729 const PetscInt *locals; 9730 const PetscSFNode *remotes; 9731 PetscBool distributed; 9732 MPI_Comm comm; 9733 PetscMPIInt rank; 9734 9735 PetscFunctionBegin; 9736 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9737 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9738 else pointSF = dm->sf; 9739 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9740 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9741 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9742 { 9743 PetscMPIInt mpiFlag; 9744 9745 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9746 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9747 } 9748 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9749 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9750 if (!distributed) { 9751 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); 9752 PetscFunctionReturn(PETSC_SUCCESS); 9753 } 9754 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); 9755 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9756 9757 /* Check SF graph is compatible with DMPlex chart */ 9758 { 9759 PetscInt pStart, pEnd, maxLeaf; 9760 9761 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9762 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9763 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9764 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9765 } 9766 9767 /* Check there are no cells in interface */ 9768 if (!overlap) { 9769 PetscInt cellHeight, cStart, cEnd; 9770 9771 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9772 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9773 for (l = 0; l < nleaves; ++l) { 9774 const PetscInt point = locals ? locals[l] : l; 9775 9776 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9777 } 9778 } 9779 9780 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9781 { 9782 const PetscInt *rootdegree; 9783 9784 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9785 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9786 for (l = 0; l < nleaves; ++l) { 9787 const PetscInt point = locals ? locals[l] : l; 9788 const PetscInt *cone; 9789 PetscInt coneSize, c, idx; 9790 9791 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9792 PetscCall(DMPlexGetCone(dm, point, &cone)); 9793 for (c = 0; c < coneSize; ++c) { 9794 if (!rootdegree[cone[c]]) { 9795 if (locals) { 9796 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9797 } else { 9798 idx = (cone[c] < nleaves) ? cone[c] : -1; 9799 } 9800 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9801 } 9802 } 9803 } 9804 } 9805 PetscFunctionReturn(PETSC_SUCCESS); 9806 } 9807 9808 /*@ 9809 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9810 9811 Collective 9812 9813 Input Parameter: 9814 . dm - The `DMPLEX` object 9815 9816 Level: developer 9817 9818 Notes: 9819 This is mainly intended for debugging/testing purposes. 9820 9821 Other cell types which are disconnected would be caught by the symmetry and face checks. 9822 9823 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9824 9825 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9826 @*/ 9827 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9828 { 9829 PetscInt pStart, pEnd, vStart, vEnd; 9830 9831 PetscFunctionBegin; 9832 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9833 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9834 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9835 for (PetscInt v = vStart; v < vEnd; ++v) { 9836 PetscInt suppSize; 9837 9838 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9839 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9840 } 9841 PetscFunctionReturn(PETSC_SUCCESS); 9842 } 9843 9844 /*@ 9845 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9846 9847 Input Parameter: 9848 . dm - The `DMPLEX` object 9849 9850 Level: developer 9851 9852 Notes: 9853 This is a useful diagnostic when creating meshes programmatically. 9854 9855 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9856 9857 Currently does not include `DMPlexCheckCellShape()`. 9858 9859 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9860 @*/ 9861 PetscErrorCode DMPlexCheck(DM dm) 9862 { 9863 PetscInt cellHeight; 9864 9865 PetscFunctionBegin; 9866 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9867 PetscCall(DMPlexCheckSymmetry(dm)); 9868 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9869 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9870 PetscCall(DMPlexCheckGeometry(dm)); 9871 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9872 PetscCall(DMPlexCheckInterfaceCones(dm)); 9873 PetscCall(DMPlexCheckOrphanVertices(dm)); 9874 PetscFunctionReturn(PETSC_SUCCESS); 9875 } 9876 9877 typedef struct cell_stats { 9878 PetscReal min, max, sum, squaresum; 9879 PetscInt count; 9880 } cell_stats_t; 9881 9882 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9883 { 9884 PetscInt i, N = *len; 9885 9886 for (i = 0; i < N; i++) { 9887 cell_stats_t *A = (cell_stats_t *)a; 9888 cell_stats_t *B = (cell_stats_t *)b; 9889 9890 B->min = PetscMin(A->min, B->min); 9891 B->max = PetscMax(A->max, B->max); 9892 B->sum += A->sum; 9893 B->squaresum += A->squaresum; 9894 B->count += A->count; 9895 } 9896 } 9897 9898 /*@ 9899 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9900 9901 Collective 9902 9903 Input Parameters: 9904 + dm - The `DMPLEX` object 9905 . output - If true, statistics will be displayed on `stdout` 9906 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9907 9908 Level: developer 9909 9910 Notes: 9911 This is mainly intended for debugging/testing purposes. 9912 9913 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9914 9915 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9916 @*/ 9917 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9918 { 9919 DM dmCoarse; 9920 cell_stats_t stats, globalStats; 9921 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9922 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9923 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9924 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9925 PetscMPIInt rank, size; 9926 9927 PetscFunctionBegin; 9928 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9929 stats.min = PETSC_MAX_REAL; 9930 stats.max = PETSC_MIN_REAL; 9931 stats.sum = stats.squaresum = 0.; 9932 stats.count = 0; 9933 9934 PetscCallMPI(MPI_Comm_size(comm, &size)); 9935 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9936 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9937 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9938 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9939 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9940 for (c = cStart; c < cEnd; c++) { 9941 PetscInt i; 9942 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9943 9944 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9945 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9946 for (i = 0; i < PetscSqr(cdim); ++i) { 9947 frobJ += J[i] * J[i]; 9948 frobInvJ += invJ[i] * invJ[i]; 9949 } 9950 cond2 = frobJ * frobInvJ; 9951 cond = PetscSqrtReal(cond2); 9952 9953 stats.min = PetscMin(stats.min, cond); 9954 stats.max = PetscMax(stats.max, cond); 9955 stats.sum += cond; 9956 stats.squaresum += cond2; 9957 stats.count++; 9958 if (output && cond > limit) { 9959 PetscSection coordSection; 9960 Vec coordsLocal; 9961 PetscScalar *coords = NULL; 9962 PetscInt Nv, d, clSize, cl, *closure = NULL; 9963 9964 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9965 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9966 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9967 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9968 for (i = 0; i < Nv / cdim; ++i) { 9969 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9970 for (d = 0; d < cdim; ++d) { 9971 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9972 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9973 } 9974 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9975 } 9976 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9977 for (cl = 0; cl < clSize * 2; cl += 2) { 9978 const PetscInt edge = closure[cl]; 9979 9980 if ((edge >= eStart) && (edge < eEnd)) { 9981 PetscReal len; 9982 9983 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9984 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9985 } 9986 } 9987 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9988 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9989 } 9990 } 9991 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9992 9993 if (size > 1) { 9994 PetscMPIInt blockLengths[2] = {4, 1}; 9995 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9996 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9997 MPI_Op statReduce; 9998 9999 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 10000 PetscCallMPI(MPI_Type_commit(&statType)); 10001 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 10002 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 10003 PetscCallMPI(MPI_Op_free(&statReduce)); 10004 PetscCallMPI(MPI_Type_free(&statType)); 10005 } else { 10006 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 10007 } 10008 if (rank == 0) { 10009 count = globalStats.count; 10010 min = globalStats.min; 10011 max = globalStats.max; 10012 mean = globalStats.sum / globalStats.count; 10013 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 10014 } 10015 10016 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)); 10017 PetscCall(PetscFree2(J, invJ)); 10018 10019 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 10020 if (dmCoarse) { 10021 PetscBool isplex; 10022 10023 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 10024 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 10025 } 10026 PetscFunctionReturn(PETSC_SUCCESS); 10027 } 10028 10029 /*@ 10030 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 10031 orthogonal quality below given tolerance. 10032 10033 Collective 10034 10035 Input Parameters: 10036 + dm - The `DMPLEX` object 10037 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 10038 - atol - [0, 1] Absolute tolerance for tagging cells. 10039 10040 Output Parameters: 10041 + OrthQual - `Vec` containing orthogonal quality per cell 10042 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 10043 10044 Options Database Keys: 10045 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 10046 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 10047 10048 Level: intermediate 10049 10050 Notes: 10051 Orthogonal quality is given by the following formula\: 10052 10053 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 10054 10055 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 10056 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 10057 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 10058 calculating the cosine of the angle between these vectors. 10059 10060 Orthogonal quality ranges from 1 (best) to 0 (worst). 10061 10062 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 10063 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 10064 10065 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 10066 10067 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 10068 @*/ 10069 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 10070 { 10071 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 10072 PetscInt *idx; 10073 PetscScalar *oqVals; 10074 const PetscScalar *cellGeomArr, *faceGeomArr; 10075 PetscReal *ci, *fi, *Ai; 10076 MPI_Comm comm; 10077 Vec cellgeom, facegeom; 10078 DM dmFace, dmCell; 10079 IS glob; 10080 ISLocalToGlobalMapping ltog; 10081 PetscViewer vwr; 10082 10083 PetscFunctionBegin; 10084 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10085 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 10086 PetscAssertPointer(OrthQual, 4); 10087 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 10088 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 10089 PetscCall(DMGetDimension(dm, &nc)); 10090 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 10091 { 10092 DMPlexInterpolatedFlag interpFlag; 10093 10094 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 10095 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 10096 PetscMPIInt rank; 10097 10098 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 10099 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 10100 } 10101 } 10102 if (OrthQualLabel) { 10103 PetscAssertPointer(OrthQualLabel, 5); 10104 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 10105 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 10106 } else { 10107 *OrthQualLabel = NULL; 10108 } 10109 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 10110 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 10111 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 10112 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 10113 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 10114 PetscCall(VecCreate(comm, OrthQual)); 10115 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 10116 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 10117 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 10118 PetscCall(VecSetUp(*OrthQual)); 10119 PetscCall(ISDestroy(&glob)); 10120 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 10121 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 10122 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 10123 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 10124 PetscCall(VecGetDM(cellgeom, &dmCell)); 10125 PetscCall(VecGetDM(facegeom, &dmFace)); 10126 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 10127 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 10128 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 10129 PetscInt cellarr[2], *adj = NULL; 10130 PetscScalar *cArr, *fArr; 10131 PetscReal minvalc = 1.0, minvalf = 1.0; 10132 PetscFVCellGeom *cg; 10133 10134 idx[cellIter] = cell - cStart; 10135 cellarr[0] = cell; 10136 /* Make indexing into cellGeom easier */ 10137 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10138 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10139 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10140 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10141 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10142 PetscInt i; 10143 const PetscInt neigh = adj[cellneigh]; 10144 PetscReal normci = 0, normfi = 0, normai = 0; 10145 PetscFVCellGeom *cgneigh; 10146 PetscFVFaceGeom *fg; 10147 10148 /* Don't count ourselves in the neighbor list */ 10149 if (neigh == cell) continue; 10150 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10151 cellarr[1] = neigh; 10152 { 10153 PetscInt numcovpts; 10154 const PetscInt *covpts; 10155 10156 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10157 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10158 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10159 } 10160 10161 /* Compute c_i, f_i and their norms */ 10162 for (i = 0; i < nc; i++) { 10163 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10164 fi[i] = fg->centroid[i] - cg->centroid[i]; 10165 Ai[i] = fg->normal[i]; 10166 normci += PetscPowReal(ci[i], 2); 10167 normfi += PetscPowReal(fi[i], 2); 10168 normai += PetscPowReal(Ai[i], 2); 10169 } 10170 normci = PetscSqrtReal(normci); 10171 normfi = PetscSqrtReal(normfi); 10172 normai = PetscSqrtReal(normai); 10173 10174 /* Normalize and compute for each face-cell-normal pair */ 10175 for (i = 0; i < nc; i++) { 10176 ci[i] = ci[i] / normci; 10177 fi[i] = fi[i] / normfi; 10178 Ai[i] = Ai[i] / normai; 10179 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10180 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10181 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10182 } 10183 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10184 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10185 } 10186 PetscCall(PetscFree(adj)); 10187 PetscCall(PetscFree2(cArr, fArr)); 10188 /* Defer to cell if they're equal */ 10189 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10190 if (OrthQualLabel) { 10191 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10192 } 10193 } 10194 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10195 PetscCall(VecAssemblyBegin(*OrthQual)); 10196 PetscCall(VecAssemblyEnd(*OrthQual)); 10197 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10198 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10199 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10200 if (OrthQualLabel) { 10201 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10202 } 10203 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10204 PetscCall(PetscViewerDestroy(&vwr)); 10205 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10206 PetscFunctionReturn(PETSC_SUCCESS); 10207 } 10208 10209 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10210 * interpolator construction */ 10211 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10212 { 10213 PetscSection section, newSection, gsection; 10214 PetscSF sf; 10215 PetscBool hasConstraints, ghasConstraints; 10216 10217 PetscFunctionBegin; 10218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10219 PetscAssertPointer(odm, 2); 10220 PetscCall(DMGetLocalSection(dm, §ion)); 10221 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10222 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10223 if (!ghasConstraints) { 10224 PetscCall(PetscObjectReference((PetscObject)dm)); 10225 *odm = dm; 10226 PetscFunctionReturn(PETSC_SUCCESS); 10227 } 10228 PetscCall(DMClone(dm, odm)); 10229 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10230 PetscCall(DMGetLocalSection(*odm, &newSection)); 10231 PetscCall(DMGetPointSF(*odm, &sf)); 10232 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10233 PetscCall(DMSetGlobalSection(*odm, gsection)); 10234 PetscCall(PetscSectionDestroy(&gsection)); 10235 PetscFunctionReturn(PETSC_SUCCESS); 10236 } 10237 10238 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10239 { 10240 DM dmco, dmfo; 10241 Mat interpo; 10242 Vec rscale; 10243 Vec cglobalo, clocal; 10244 Vec fglobal, fglobalo, flocal; 10245 PetscBool regular; 10246 10247 PetscFunctionBegin; 10248 PetscCall(DMGetFullDM(dmc, &dmco)); 10249 PetscCall(DMGetFullDM(dmf, &dmfo)); 10250 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10251 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10252 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10253 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10254 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10255 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10256 PetscCall(VecSet(cglobalo, 0.)); 10257 PetscCall(VecSet(clocal, 0.)); 10258 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10259 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10260 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10261 PetscCall(VecSet(fglobal, 0.)); 10262 PetscCall(VecSet(fglobalo, 0.)); 10263 PetscCall(VecSet(flocal, 0.)); 10264 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10265 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10266 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10267 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10268 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10269 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10270 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10271 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10272 *shift = fglobal; 10273 PetscCall(VecDestroy(&flocal)); 10274 PetscCall(VecDestroy(&fglobalo)); 10275 PetscCall(VecDestroy(&clocal)); 10276 PetscCall(VecDestroy(&cglobalo)); 10277 PetscCall(VecDestroy(&rscale)); 10278 PetscCall(MatDestroy(&interpo)); 10279 PetscCall(DMDestroy(&dmfo)); 10280 PetscCall(DMDestroy(&dmco)); 10281 PetscFunctionReturn(PETSC_SUCCESS); 10282 } 10283 10284 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10285 { 10286 PetscObject shifto; 10287 Vec shift; 10288 10289 PetscFunctionBegin; 10290 if (!interp) { 10291 Vec rscale; 10292 10293 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10294 PetscCall(VecDestroy(&rscale)); 10295 } else { 10296 PetscCall(PetscObjectReference((PetscObject)interp)); 10297 } 10298 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10299 if (!shifto) { 10300 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10301 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10302 shifto = (PetscObject)shift; 10303 PetscCall(VecDestroy(&shift)); 10304 } 10305 shift = (Vec)shifto; 10306 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10307 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10308 PetscCall(MatDestroy(&interp)); 10309 PetscFunctionReturn(PETSC_SUCCESS); 10310 } 10311 10312 /* Pointwise interpolation 10313 Just code FEM for now 10314 u^f = I u^c 10315 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10316 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10317 I_{ij} = psi^f_i phi^c_j 10318 */ 10319 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10320 { 10321 PetscSection gsc, gsf; 10322 PetscInt m, n; 10323 void *ctx; 10324 DM cdm; 10325 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10326 10327 PetscFunctionBegin; 10328 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10329 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10330 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10331 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10332 10333 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10334 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10335 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10336 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10337 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10338 10339 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10340 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10341 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10342 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10343 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10344 if (scaling) { 10345 /* Use naive scaling */ 10346 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10347 } 10348 PetscFunctionReturn(PETSC_SUCCESS); 10349 } 10350 10351 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10352 { 10353 VecScatter ctx; 10354 10355 PetscFunctionBegin; 10356 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10357 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10358 PetscCall(VecScatterDestroy(&ctx)); 10359 PetscFunctionReturn(PETSC_SUCCESS); 10360 } 10361 10362 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[]) 10363 { 10364 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10365 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10366 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10367 } 10368 10369 // The assumption here is that the test field is a vector and the basis field is a scalar (so we need the gradient) 10370 static void g1_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 g1[]) 10371 { 10372 for (PetscInt c = 0; c < dim; ++c) g1[c * dim + c] = 1.0; 10373 } 10374 10375 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10376 { 10377 DM dmc; 10378 PetscDS ds; 10379 Vec ones, locmass; 10380 IS cellIS; 10381 PetscFormKey key; 10382 PetscInt depth; 10383 10384 PetscFunctionBegin; 10385 PetscCall(DMClone(dm, &dmc)); 10386 PetscCall(DMCopyDisc(dm, dmc)); 10387 PetscCall(DMGetDS(dmc, &ds)); 10388 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10389 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10390 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10391 else PetscCall(DMGetLocalVector(dm, &locmass)); 10392 PetscCall(DMGetLocalVector(dm, &ones)); 10393 PetscCall(DMPlexGetDepth(dm, &depth)); 10394 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10395 PetscCall(VecSet(locmass, 0.0)); 10396 PetscCall(VecSet(ones, 1.0)); 10397 key.label = NULL; 10398 key.value = 0; 10399 key.field = 0; 10400 key.part = 0; 10401 PetscCall(DMPlexComputeJacobianActionByKey(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10402 PetscCall(ISDestroy(&cellIS)); 10403 if (mass) { 10404 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10405 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10406 } 10407 PetscCall(DMRestoreLocalVector(dm, &ones)); 10408 if (lmass) *lmass = locmass; 10409 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10410 PetscCall(DMDestroy(&dmc)); 10411 PetscFunctionReturn(PETSC_SUCCESS); 10412 } 10413 10414 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10415 { 10416 PetscSection gsc, gsf; 10417 PetscInt m, n; 10418 void *ctx; 10419 DM cdm; 10420 PetscBool regular; 10421 10422 PetscFunctionBegin; 10423 if (dmFine == dmCoarse) { 10424 DM dmc; 10425 PetscDS ds; 10426 PetscWeakForm wf; 10427 Vec u; 10428 IS cellIS; 10429 PetscFormKey key; 10430 PetscInt depth; 10431 10432 PetscCall(DMClone(dmFine, &dmc)); 10433 PetscCall(DMCopyDisc(dmFine, dmc)); 10434 PetscCall(DMGetDS(dmc, &ds)); 10435 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10436 PetscCall(PetscWeakFormClear(wf)); 10437 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10438 PetscCall(DMCreateMatrix(dmc, mass)); 10439 PetscCall(DMGetLocalVector(dmc, &u)); 10440 PetscCall(DMPlexGetDepth(dmc, &depth)); 10441 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10442 PetscCall(MatZeroEntries(*mass)); 10443 key.label = NULL; 10444 key.value = 0; 10445 key.field = 0; 10446 key.part = 0; 10447 PetscCall(DMPlexComputeJacobianByKey(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10448 PetscCall(ISDestroy(&cellIS)); 10449 PetscCall(DMRestoreLocalVector(dmc, &u)); 10450 PetscCall(DMDestroy(&dmc)); 10451 } else { 10452 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10453 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10454 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10455 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10456 10457 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10458 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10459 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10460 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10461 10462 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10463 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10464 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10465 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10466 } 10467 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10468 PetscFunctionReturn(PETSC_SUCCESS); 10469 } 10470 10471 PetscErrorCode DMCreateGradientMatrix_Plex(DM dmc, DM dmr, Mat *derv) 10472 { 10473 PetscSection gsc, gsf; 10474 PetscInt m, n; 10475 void *ctx; 10476 10477 PetscFunctionBegin; 10478 PetscCall(DMGetGlobalSection(dmr, &gsf)); 10479 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10480 PetscCall(DMGetGlobalSection(dmc, &gsc)); 10481 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10482 10483 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmc), derv)); 10484 PetscCall(PetscObjectSetName((PetscObject)*derv, "Plex Derivative Matrix")); 10485 PetscCall(MatSetSizes(*derv, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10486 PetscCall(MatSetType(*derv, dmc->mattype)); 10487 10488 PetscCall(DMGetApplicationContext(dmr, &ctx)); 10489 { 10490 DM ndmr; 10491 PetscDS ds; 10492 PetscWeakForm wf; 10493 Vec u; 10494 IS cellIS; 10495 PetscFormKey key; 10496 PetscInt depth, Nf; 10497 10498 PetscCall(DMClone(dmr, &ndmr)); 10499 PetscCall(DMCopyDisc(dmr, ndmr)); 10500 PetscCall(DMGetDS(ndmr, &ds)); 10501 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10502 PetscCall(PetscWeakFormClear(wf)); 10503 PetscCall(PetscDSGetNumFields(ds, &Nf)); 10504 for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, NULL, g1_identity_private, NULL, NULL)); 10505 PetscCall(DMGetLocalVector(ndmr, &u)); 10506 PetscCall(DMPlexGetDepth(ndmr, &depth)); 10507 PetscCall(DMGetStratumIS(ndmr, "depth", depth, &cellIS)); 10508 PetscCall(MatZeroEntries(*derv)); 10509 key.label = NULL; 10510 key.value = 0; 10511 key.field = 0; 10512 key.part = 0; 10513 PetscCall(DMPlexComputeJacobianByKeyGeneral(ndmr, dmc, key, cellIS, 0.0, 0.0, u, NULL, *derv, *derv, NULL)); 10514 PetscCall(ISDestroy(&cellIS)); 10515 PetscCall(DMRestoreLocalVector(ndmr, &u)); 10516 PetscCall(DMDestroy(&ndmr)); 10517 } 10518 PetscCall(MatViewFromOptions(*derv, NULL, "-gradient_mat_view")); 10519 PetscFunctionReturn(PETSC_SUCCESS); 10520 } 10521 10522 /*@ 10523 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10524 10525 Input Parameter: 10526 . dm - The `DMPLEX` object 10527 10528 Output Parameter: 10529 . regular - The flag 10530 10531 Level: intermediate 10532 10533 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10534 @*/ 10535 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10536 { 10537 PetscFunctionBegin; 10538 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10539 PetscAssertPointer(regular, 2); 10540 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10541 PetscFunctionReturn(PETSC_SUCCESS); 10542 } 10543 10544 /*@ 10545 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10546 10547 Input Parameters: 10548 + dm - The `DMPLEX` object 10549 - regular - The flag 10550 10551 Level: intermediate 10552 10553 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10554 @*/ 10555 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10556 { 10557 PetscFunctionBegin; 10558 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10559 ((DM_Plex *)dm->data)->regularRefinement = regular; 10560 PetscFunctionReturn(PETSC_SUCCESS); 10561 } 10562 10563 /*@ 10564 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10565 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10566 10567 Not Collective 10568 10569 Input Parameter: 10570 . dm - The `DMPLEX` object 10571 10572 Output Parameters: 10573 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10574 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10575 10576 Level: intermediate 10577 10578 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10579 @*/ 10580 PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS) 10581 { 10582 DM_Plex *plex = (DM_Plex *)dm->data; 10583 10584 PetscFunctionBegin; 10585 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10586 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10587 if (anchorSection) *anchorSection = plex->anchorSection; 10588 if (anchorIS) *anchorIS = plex->anchorIS; 10589 PetscFunctionReturn(PETSC_SUCCESS); 10590 } 10591 10592 /*@ 10593 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10594 10595 Collective 10596 10597 Input Parameters: 10598 + dm - The `DMPLEX` object 10599 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10600 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10601 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10602 10603 Level: intermediate 10604 10605 Notes: 10606 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10607 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10608 combination of other points' degrees of freedom. 10609 10610 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10611 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10612 10613 The reference counts of `anchorSection` and `anchorIS` are incremented. 10614 10615 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10616 @*/ 10617 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10618 { 10619 DM_Plex *plex = (DM_Plex *)dm->data; 10620 PetscMPIInt result; 10621 10622 PetscFunctionBegin; 10623 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10624 if (anchorSection) { 10625 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10626 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10627 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10628 } 10629 if (anchorIS) { 10630 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10631 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10632 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10633 } 10634 10635 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10636 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10637 plex->anchorSection = anchorSection; 10638 10639 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10640 PetscCall(ISDestroy(&plex->anchorIS)); 10641 plex->anchorIS = anchorIS; 10642 10643 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10644 PetscInt size, a, pStart, pEnd; 10645 const PetscInt *anchors; 10646 10647 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10648 PetscCall(ISGetLocalSize(anchorIS, &size)); 10649 PetscCall(ISGetIndices(anchorIS, &anchors)); 10650 for (a = 0; a < size; a++) { 10651 PetscInt p; 10652 10653 p = anchors[a]; 10654 if (p >= pStart && p < pEnd) { 10655 PetscInt dof; 10656 10657 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10658 if (dof) { 10659 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10660 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10661 } 10662 } 10663 } 10664 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10665 } 10666 /* reset the generic constraints */ 10667 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10668 PetscFunctionReturn(PETSC_SUCCESS); 10669 } 10670 10671 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10672 { 10673 PetscSection anchorSection; 10674 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10675 10676 PetscFunctionBegin; 10677 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10678 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10679 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10680 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10681 if (numFields) { 10682 PetscInt f; 10683 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10684 10685 for (f = 0; f < numFields; f++) { 10686 PetscInt numComp; 10687 10688 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10689 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10690 } 10691 } 10692 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10693 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10694 pStart = PetscMax(pStart, sStart); 10695 pEnd = PetscMin(pEnd, sEnd); 10696 pEnd = PetscMax(pStart, pEnd); 10697 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10698 for (p = pStart; p < pEnd; p++) { 10699 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10700 if (dof) { 10701 PetscCall(PetscSectionGetDof(section, p, &dof)); 10702 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10703 for (f = 0; f < numFields; f++) { 10704 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10705 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10706 } 10707 } 10708 } 10709 PetscCall(PetscSectionSetUp(*cSec)); 10710 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10711 PetscFunctionReturn(PETSC_SUCCESS); 10712 } 10713 10714 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10715 { 10716 PetscSection aSec; 10717 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10718 const PetscInt *anchors; 10719 PetscInt numFields, f; 10720 IS aIS; 10721 MatType mtype; 10722 PetscBool iscuda, iskokkos; 10723 10724 PetscFunctionBegin; 10725 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10726 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10727 PetscCall(PetscSectionGetStorageSize(section, &n)); 10728 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10729 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10730 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10731 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10732 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10733 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10734 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10735 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10736 else mtype = MATSEQAIJ; 10737 PetscCall(MatSetType(*cMat, mtype)); 10738 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10739 PetscCall(ISGetIndices(aIS, &anchors)); 10740 /* cSec will be a subset of aSec and section */ 10741 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10742 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10743 PetscCall(PetscMalloc1(m + 1, &i)); 10744 i[0] = 0; 10745 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10746 for (p = pStart; p < pEnd; p++) { 10747 PetscInt rDof, rOff, r; 10748 10749 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10750 if (!rDof) continue; 10751 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10752 if (numFields) { 10753 for (f = 0; f < numFields; f++) { 10754 annz = 0; 10755 for (r = 0; r < rDof; r++) { 10756 a = anchors[rOff + r]; 10757 if (a < sStart || a >= sEnd) continue; 10758 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10759 annz += aDof; 10760 } 10761 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10762 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10763 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10764 } 10765 } else { 10766 annz = 0; 10767 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10768 for (q = 0; q < dof; q++) { 10769 a = anchors[rOff + q]; 10770 if (a < sStart || a >= sEnd) continue; 10771 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10772 annz += aDof; 10773 } 10774 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10775 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10776 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10777 } 10778 } 10779 nnz = i[m]; 10780 PetscCall(PetscMalloc1(nnz, &j)); 10781 offset = 0; 10782 for (p = pStart; p < pEnd; p++) { 10783 if (numFields) { 10784 for (f = 0; f < numFields; f++) { 10785 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10786 for (q = 0; q < dof; q++) { 10787 PetscInt rDof, rOff, r; 10788 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10789 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10790 for (r = 0; r < rDof; r++) { 10791 PetscInt s; 10792 10793 a = anchors[rOff + r]; 10794 if (a < sStart || a >= sEnd) continue; 10795 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10796 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10797 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10798 } 10799 } 10800 } 10801 } else { 10802 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10803 for (q = 0; q < dof; q++) { 10804 PetscInt rDof, rOff, r; 10805 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10806 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10807 for (r = 0; r < rDof; r++) { 10808 PetscInt s; 10809 10810 a = anchors[rOff + r]; 10811 if (a < sStart || a >= sEnd) continue; 10812 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10813 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10814 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10815 } 10816 } 10817 } 10818 } 10819 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10820 PetscCall(PetscFree(i)); 10821 PetscCall(PetscFree(j)); 10822 PetscCall(ISRestoreIndices(aIS, &anchors)); 10823 PetscFunctionReturn(PETSC_SUCCESS); 10824 } 10825 10826 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10827 { 10828 DM_Plex *plex = (DM_Plex *)dm->data; 10829 PetscSection anchorSection, section, cSec; 10830 Mat cMat; 10831 10832 PetscFunctionBegin; 10833 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10834 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10835 if (anchorSection) { 10836 PetscInt Nf; 10837 10838 PetscCall(DMGetLocalSection(dm, §ion)); 10839 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10840 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10841 PetscCall(DMGetNumFields(dm, &Nf)); 10842 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10843 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10844 PetscCall(PetscSectionDestroy(&cSec)); 10845 PetscCall(MatDestroy(&cMat)); 10846 } 10847 PetscFunctionReturn(PETSC_SUCCESS); 10848 } 10849 10850 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10851 { 10852 IS subis; 10853 PetscSection section, subsection; 10854 10855 PetscFunctionBegin; 10856 PetscCall(DMGetLocalSection(dm, §ion)); 10857 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10858 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10859 /* Create subdomain */ 10860 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, PetscObjectComm((PetscObject)dm), NULL, subdm)); 10861 /* Create submodel */ 10862 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10863 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10864 PetscCall(DMSetLocalSection(*subdm, subsection)); 10865 PetscCall(PetscSectionDestroy(&subsection)); 10866 PetscCall(DMCopyDisc(dm, *subdm)); 10867 /* Create map from submodel to global model */ 10868 if (is) { 10869 PetscSection sectionGlobal, subsectionGlobal; 10870 IS spIS; 10871 const PetscInt *spmap; 10872 PetscInt *subIndices; 10873 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10874 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10875 10876 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10877 PetscCall(ISGetIndices(spIS, &spmap)); 10878 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10879 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10880 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10881 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10882 for (p = pStart; p < pEnd; ++p) { 10883 PetscInt gdof, pSubSize = 0; 10884 10885 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10886 if (gdof > 0) { 10887 for (f = 0; f < Nf; ++f) { 10888 PetscInt fdof, fcdof; 10889 10890 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10891 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10892 pSubSize += fdof - fcdof; 10893 } 10894 subSize += pSubSize; 10895 if (pSubSize) { 10896 if (bs < 0) { 10897 bs = pSubSize; 10898 } else if (bs != pSubSize) { 10899 /* Layout does not admit a pointwise block size */ 10900 bs = 1; 10901 } 10902 } 10903 } 10904 } 10905 /* Must have same blocksize on all procs (some might have no points) */ 10906 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10907 bsLocal[1] = bs; 10908 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10909 if (bsMinMax[0] != bsMinMax[1]) { 10910 bs = 1; 10911 } else { 10912 bs = bsMinMax[0]; 10913 } 10914 PetscCall(PetscMalloc1(subSize, &subIndices)); 10915 for (p = pStart; p < pEnd; ++p) { 10916 PetscInt gdof, goff; 10917 10918 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10919 if (gdof > 0) { 10920 const PetscInt point = spmap[p]; 10921 10922 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10923 for (f = 0; f < Nf; ++f) { 10924 PetscInt fdof, fcdof, fc, f2, poff = 0; 10925 10926 /* Can get rid of this loop by storing field information in the global section */ 10927 for (f2 = 0; f2 < f; ++f2) { 10928 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10929 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10930 poff += fdof - fcdof; 10931 } 10932 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10933 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10934 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10935 } 10936 } 10937 } 10938 PetscCall(ISRestoreIndices(spIS, &spmap)); 10939 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10940 if (bs > 1) { 10941 /* We need to check that the block size does not come from non-contiguous fields */ 10942 PetscInt i, j, set = 1; 10943 for (i = 0; i < subSize; i += bs) { 10944 for (j = 0; j < bs; ++j) { 10945 if (subIndices[i + j] != subIndices[i] + j) { 10946 set = 0; 10947 break; 10948 } 10949 } 10950 } 10951 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10952 } 10953 // Attach nullspace 10954 if (dm->nullspaceConstructors) { 10955 for (f = 0; f < Nf; ++f) { 10956 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10957 if ((*subdm)->nullspaceConstructors[f]) break; 10958 } 10959 if (f < Nf) { 10960 MatNullSpace nullSpace; 10961 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10962 10963 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10964 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10965 } 10966 } 10967 } 10968 PetscFunctionReturn(PETSC_SUCCESS); 10969 } 10970 10971 /*@ 10972 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10973 10974 Input Parameters: 10975 + dm - The `DM` 10976 - unused - unused argument 10977 10978 Options Database Key: 10979 . -dm_plex_monitor_throughput - Activate the monitor 10980 10981 Level: developer 10982 10983 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10984 @*/ 10985 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *unused) 10986 { 10987 PetscLogHandler default_handler; 10988 10989 PetscFunctionBegin; 10990 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10991 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10992 if (default_handler) { 10993 PetscLogEvent event; 10994 PetscEventPerfInfo eventInfo; 10995 PetscLogDouble cellRate, flopRate; 10996 PetscInt cStart, cEnd, Nf, N; 10997 const char *name; 10998 10999 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 11000 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 11001 PetscCall(DMGetNumFields(dm, &Nf)); 11002 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 11003 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 11004 N = (cEnd - cStart) * Nf * eventInfo.count; 11005 flopRate = eventInfo.flops / eventInfo.time; 11006 cellRate = N / eventInfo.time; 11007 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, cellRate, flopRate / 1.e6)); 11008 } else { 11009 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."); 11010 } 11011 PetscFunctionReturn(PETSC_SUCCESS); 11012 } 11013