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