1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeMultistage, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_CreateBoxSFC, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 PetscLogEvent DMPLEX_DistributionView, DMPLEX_DistributionLoad; 17 18 PetscBool Plexcite = PETSC_FALSE; 19 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 20 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 21 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 22 "journal = {SIAM Journal on Scientific Computing},\n" 23 "volume = {38},\n" 24 "number = {5},\n" 25 "pages = {S143--S155},\n" 26 "eprint = {http://arxiv.org/abs/1506.07749},\n" 27 "doi = {10.1137/15M1026092},\n" 28 "year = {2016},\n" 29 "petsc_uses={DMPlex},\n}\n"; 30 31 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 32 33 /*@ 34 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 35 36 Input Parameter: 37 . dm - The `DMPLEX` object 38 39 Output Parameter: 40 . simplex - Flag checking for a simplex 41 42 Level: intermediate 43 44 Note: 45 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 46 If the mesh has no cells, this returns `PETSC_FALSE`. 47 48 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 49 @*/ 50 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 51 { 52 DMPolytopeType ct; 53 PetscInt cStart, cEnd; 54 55 PetscFunctionBegin; 56 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 57 if (cEnd <= cStart) { 58 *simplex = PETSC_FALSE; 59 PetscFunctionReturn(PETSC_SUCCESS); 60 } 61 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 62 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 63 PetscFunctionReturn(PETSC_SUCCESS); 64 } 65 66 /*@ 67 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 68 69 Input Parameters: 70 + dm - The `DMPLEX` object 71 - height - The cell height in the Plex, 0 is the default 72 73 Output Parameters: 74 + cStart - The first "normal" cell, pass `NULL` if not needed 75 - cEnd - The upper bound on "normal" cells, pass `NULL` if not needed 76 77 Level: developer 78 79 Note: 80 This function requires that tensor cells are ordered last. 81 82 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 83 @*/ 84 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PeOp PetscInt *cStart, PeOp PetscInt *cEnd) 85 { 86 DMLabel ctLabel; 87 IS valueIS; 88 const PetscInt *ctypes; 89 PetscBool found = PETSC_FALSE; 90 PetscInt Nct, cS = PETSC_INT_MAX, cE = 0; 91 92 PetscFunctionBegin; 93 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 94 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 95 PetscCall(ISGetLocalSize(valueIS, &Nct)); 96 PetscCall(ISGetIndices(valueIS, &ctypes)); 97 for (PetscInt t = 0; t < Nct; ++t) { 98 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 99 PetscInt ctS, ctE, ht; 100 101 if (ct == DM_POLYTOPE_UNKNOWN) { 102 // If any cells are not typed, just use all cells 103 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 104 break; 105 } 106 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 107 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 108 if (ctS >= ctE) continue; 109 // Check that a point has the right height 110 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 111 if (ht != height) continue; 112 cS = PetscMin(cS, ctS); 113 cE = PetscMax(cE, ctE); 114 found = PETSC_TRUE; 115 } 116 if (!Nct || !found) cS = cE = 0; 117 PetscCall(ISDestroy(&valueIS)); 118 // Reset label for fast lookup 119 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 120 if (cStart) *cStart = cS; 121 if (cEnd) *cEnd = cE; 122 PetscFunctionReturn(PETSC_SUCCESS); 123 } 124 125 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 126 { 127 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 128 PetscInt *sStart, *sEnd; 129 PetscViewerVTKFieldType *ft; 130 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 131 DMLabel depthLabel, ctLabel; 132 133 PetscFunctionBegin; 134 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 135 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 136 PetscCall(DMGetCoordinateDim(dm, &cdim)); 137 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 138 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 139 if (field >= 0) { 140 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 141 } else { 142 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 143 } 144 145 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 146 PetscCall(DMPlexGetDepth(dm, &depth)); 147 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 148 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 149 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 150 const DMPolytopeType ict = (DMPolytopeType)c; 151 PetscInt dep; 152 153 if (ict == DM_POLYTOPE_FV_GHOST) continue; 154 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 155 if (pStart >= 0) { 156 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 157 if (dep != depth - cellHeight) continue; 158 } 159 if (field >= 0) { 160 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 161 } else { 162 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 163 } 164 } 165 166 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 167 *types = 0; 168 169 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 170 if (globalvcdof[c]) ++(*types); 171 } 172 173 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 174 t = 0; 175 if (globalvcdof[DM_NUM_POLYTOPES]) { 176 sStart[t] = vStart; 177 sEnd[t] = vEnd; 178 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 179 ++t; 180 } 181 182 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 183 if (globalvcdof[c]) { 184 const DMPolytopeType ict = (DMPolytopeType)c; 185 186 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 187 sStart[t] = cStart; 188 sEnd[t] = cEnd; 189 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 190 ++t; 191 } 192 } 193 194 if (!*types) { 195 if (field >= 0) { 196 const char *fieldname; 197 198 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 199 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 200 } else { 201 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 202 } 203 } 204 205 *ssStart = sStart; 206 *ssEnd = sEnd; 207 *sft = ft; 208 PetscFunctionReturn(PETSC_SUCCESS); 209 } 210 211 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 212 { 213 PetscFunctionBegin; 214 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 215 PetscFunctionReturn(PETSC_SUCCESS); 216 } 217 218 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 219 { 220 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 221 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 222 223 PetscFunctionBegin; 224 *ft = PETSC_VTK_INVALID; 225 PetscCall(DMGetCoordinateDim(dm, &cdim)); 226 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 227 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 228 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 229 if (field >= 0) { 230 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 231 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 232 } else { 233 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 234 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 235 } 236 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 237 if (globalvcdof[0]) { 238 *sStart = vStart; 239 *sEnd = vEnd; 240 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 241 else *ft = PETSC_VTK_POINT_FIELD; 242 } else if (globalvcdof[1]) { 243 *sStart = cStart; 244 *sEnd = cEnd; 245 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 246 else *ft = PETSC_VTK_CELL_FIELD; 247 } else { 248 if (field >= 0) { 249 const char *fieldname; 250 251 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 252 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 253 } else { 254 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n")); 255 } 256 } 257 PetscFunctionReturn(PETSC_SUCCESS); 258 } 259 260 /*@ 261 DMPlexVecView1D - Plot many 1D solutions on the same line graph 262 263 Collective 264 265 Input Parameters: 266 + dm - The `DMPLEX` object 267 . n - The number of vectors 268 . u - The array of local vectors 269 - viewer - The `PetscViewer` 270 271 Level: advanced 272 273 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 274 @*/ 275 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 276 { 277 DM cdm; 278 PetscDS ds; 279 PetscDraw draw = NULL; 280 PetscDrawLG lg; 281 Vec coordinates; 282 const PetscScalar *coords, **sol; 283 PetscReal *vals; 284 PetscInt *Nc; 285 PetscInt Nf, Nl, vStart, vEnd, eStart, eEnd; 286 char **names; 287 288 PetscFunctionBegin; 289 PetscCall(DMGetCoordinateDM(dm, &cdm)); 290 PetscCall(DMGetDS(dm, &ds)); 291 PetscCall(PetscDSGetNumFields(ds, &Nf)); 292 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 293 PetscCall(PetscDSGetComponents(ds, &Nc)); 294 295 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 296 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 297 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 298 299 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 300 for (PetscInt i = 0, l = 0; i < n; ++i) { 301 const char *vname; 302 303 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 304 for (PetscInt f = 0; f < Nf; ++f) { 305 PetscObject disc; 306 const char *fname; 307 char tmpname[PETSC_MAX_PATH_LEN]; 308 309 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 310 /* TODO Create names for components */ 311 for (PetscInt c = 0; c < Nc[f]; ++c, ++l) { 312 PetscCall(PetscObjectGetName(disc, &fname)); 313 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 314 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 315 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 316 PetscCall(PetscStrallocpy(tmpname, &names[l])); 317 } 318 } 319 } 320 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 321 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 322 PetscCall(VecGetArrayRead(coordinates, &coords)); 323 for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 324 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 325 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 326 PetscSection s; 327 PetscInt cdof, vdof; 328 329 PetscCall(DMGetLocalSection(dm, &s)); 330 PetscCall(PetscSectionGetDof(s, eStart, &cdof)); 331 PetscCall(PetscSectionGetDof(s, vStart, &vdof)); 332 if (cdof) { 333 if (vdof) { 334 // P_2 335 PetscInt vFirst = -1; 336 337 for (PetscInt e = eStart; e < eEnd; ++e) { 338 PetscScalar *xa, *xb, *svals; 339 const PetscInt *cone; 340 341 PetscCall(DMPlexGetCone(dm, e, &cone)); 342 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 343 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 344 if (e == eStart) vFirst = cone[0]; 345 for (PetscInt i = 0; i < n; ++i) { 346 PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals)); 347 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 348 } 349 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals)); 350 if (e == eEnd - 1 && cone[1] != vFirst) { 351 for (PetscInt i = 0; i < n; ++i) { 352 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 353 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 354 } 355 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 356 for (PetscInt i = 0; i < n; ++i) { 357 PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals)); 358 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 359 } 360 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals)); 361 } 362 } 363 } else { 364 // P_0 365 for (PetscInt e = eStart; e < eEnd; ++e) { 366 PetscScalar *xa, *xb, *svals; 367 const PetscInt *cone; 368 369 PetscCall(DMPlexGetCone(dm, e, &cone)); 370 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 371 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 372 for (PetscInt i = 0; i < n; ++i) { 373 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 374 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 375 } 376 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 377 } 378 } 379 } else if (vdof) { 380 // P_1 381 for (PetscInt v = vStart; v < vEnd; ++v) { 382 PetscScalar *x, *svals; 383 384 PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x)); 385 for (PetscInt i = 0; i < n; ++i) { 386 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 387 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 388 } 389 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 390 } 391 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Discretization not supported"); 392 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 393 for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 394 for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 395 PetscCall(PetscFree3(sol, names, vals)); 396 397 PetscCall(PetscDrawLGDraw(lg)); 398 PetscCall(PetscDrawLGDestroy(&lg)); 399 PetscFunctionReturn(PETSC_SUCCESS); 400 } 401 402 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 403 { 404 DM dm; 405 406 PetscFunctionBegin; 407 PetscCall(VecGetDM(u, &dm)); 408 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 409 PetscFunctionReturn(PETSC_SUCCESS); 410 } 411 412 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 413 { 414 DM dm; 415 PetscSection s; 416 PetscDraw draw, popup; 417 DM cdm; 418 PetscSection coordSection; 419 Vec coordinates; 420 const PetscScalar *array; 421 PetscReal lbound[3], ubound[3]; 422 PetscReal vbound[2], time; 423 PetscBool flg; 424 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 425 const char *name; 426 char title[PETSC_MAX_PATH_LEN]; 427 428 PetscFunctionBegin; 429 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 430 PetscCall(VecGetDM(v, &dm)); 431 PetscCall(DMGetCoordinateDim(dm, &dim)); 432 PetscCall(DMGetLocalSection(dm, &s)); 433 PetscCall(PetscSectionGetNumFields(s, &Nf)); 434 PetscCall(DMGetCoarsenLevel(dm, &level)); 435 PetscCall(DMGetCoordinateDM(dm, &cdm)); 436 PetscCall(DMGetLocalSection(cdm, &coordSection)); 437 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 438 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 439 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 440 441 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 442 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 443 444 PetscCall(VecGetLocalSize(coordinates, &N)); 445 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 446 PetscCall(PetscDrawClear(draw)); 447 448 /* Could implement something like DMDASelectFields() */ 449 for (f = 0; f < Nf; ++f) { 450 DM fdm = dm; 451 Vec fv = v; 452 IS fis; 453 char prefix[PETSC_MAX_PATH_LEN]; 454 const char *fname; 455 456 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 457 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 458 459 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 460 else prefix[0] = '\0'; 461 if (Nf > 1) { 462 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 463 PetscCall(VecGetSubVector(v, fis, &fv)); 464 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 465 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 466 } 467 for (comp = 0; comp < Nc; ++comp, ++w) { 468 PetscInt nmax = 2; 469 470 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 471 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 472 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 473 PetscCall(PetscDrawSetTitle(draw, title)); 474 475 /* TODO Get max and min only for this component */ 476 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 477 if (!flg) { 478 PetscCall(VecMin(fv, NULL, &vbound[0])); 479 PetscCall(VecMax(fv, NULL, &vbound[1])); 480 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 481 } 482 483 PetscCall(PetscDrawGetPopup(draw, &popup)); 484 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 485 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 486 PetscCall(VecGetArrayRead(fv, &array)); 487 for (c = cStart; c < cEnd; ++c) { 488 DMPolytopeType ct; 489 PetscScalar *coords = NULL, *a = NULL; 490 const PetscScalar *coords_arr; 491 PetscBool isDG; 492 PetscInt numCoords; 493 int color[4] = {-1, -1, -1, -1}; 494 495 PetscCall(DMPlexGetCellType(dm, c, &ct)); 496 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 497 if (a) { 498 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 499 color[1] = color[2] = color[3] = color[0]; 500 } else { 501 PetscScalar *vals = NULL; 502 PetscInt numVals, va; 503 504 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 505 if (!numVals) { 506 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 507 continue; 508 } 509 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 510 switch (numVals / Nc) { 511 case 1: /* P1 Clamped Segment Prism */ 512 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 513 PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]); 514 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 515 break; 516 case 3: /* P1 Triangle */ 517 case 4: /* P1 Quadrangle */ 518 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 519 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 520 break; 521 case 6: /* P2 Triangle */ 522 case 8: /* P2 Quadrangle */ 523 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 524 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 525 break; 526 default: 527 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 528 } 529 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 530 } 531 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 532 switch (numCoords) { 533 case 6: 534 case 12: /* Localized triangle */ 535 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 536 break; 537 case 8: 538 case 16: /* Localized quadrilateral */ 539 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 540 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 541 } else { 542 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 543 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 544 } 545 break; 546 default: 547 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 548 } 549 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 550 } 551 PetscCall(VecRestoreArrayRead(fv, &array)); 552 PetscCall(PetscDrawFlush(draw)); 553 PetscCall(PetscDrawPause(draw)); 554 PetscCall(PetscDrawSave(draw)); 555 } 556 if (Nf > 1) { 557 PetscCall(VecRestoreSubVector(v, fis, &fv)); 558 PetscCall(ISDestroy(&fis)); 559 PetscCall(DMDestroy(&fdm)); 560 } 561 } 562 PetscFunctionReturn(PETSC_SUCCESS); 563 } 564 565 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 566 { 567 DM dm; 568 PetscDraw draw; 569 PetscInt dim; 570 PetscBool isnull; 571 572 PetscFunctionBegin; 573 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 574 PetscCall(PetscDrawIsNull(draw, &isnull)); 575 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 576 577 PetscCall(VecGetDM(v, &dm)); 578 PetscCall(DMGetCoordinateDim(dm, &dim)); 579 switch (dim) { 580 case 1: 581 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 582 break; 583 case 2: 584 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 585 break; 586 default: 587 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 588 } 589 PetscFunctionReturn(PETSC_SUCCESS); 590 } 591 592 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 593 { 594 DM dm; 595 Vec locv; 596 const char *name; 597 PetscSection section; 598 PetscInt pStart, pEnd; 599 PetscInt numFields; 600 PetscViewerVTKFieldType ft; 601 602 PetscFunctionBegin; 603 PetscCall(VecGetDM(v, &dm)); 604 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 605 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 606 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 607 PetscCall(VecCopy(v, locv)); 608 PetscCall(DMGetLocalSection(dm, §ion)); 609 PetscCall(PetscSectionGetNumFields(section, &numFields)); 610 if (!numFields) { 611 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 612 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 613 } else { 614 PetscInt f; 615 616 for (f = 0; f < numFields; f++) { 617 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 618 if (ft == PETSC_VTK_INVALID) continue; 619 PetscCall(PetscObjectReference((PetscObject)locv)); 620 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 621 } 622 PetscCall(VecDestroy(&locv)); 623 } 624 PetscFunctionReturn(PETSC_SUCCESS); 625 } 626 627 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 640 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 641 if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) { 642 PetscInt i, numFields; 643 PetscObject fe; 644 PetscBool fem = PETSC_FALSE; 645 Vec locv = v; 646 const char *name; 647 PetscInt step; 648 PetscReal time; 649 650 PetscCall(DMGetNumFields(dm, &numFields)); 651 for (i = 0; i < numFields; i++) { 652 PetscCall(DMGetField(dm, i, NULL, &fe)); 653 if (fe->classid == PETSCFE_CLASSID) { 654 fem = PETSC_TRUE; 655 break; 656 } 657 } 658 if (fem) { 659 PetscObject isZero; 660 661 PetscCall(DMGetLocalVector(dm, &locv)); 662 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 663 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 664 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 665 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 666 PetscCall(VecCopy(v, locv)); 667 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 668 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 669 } 670 if (isvtk) { 671 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 672 } else if (ishdf5) { 673 #if defined(PETSC_HAVE_HDF5) 674 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 675 #else 676 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 677 #endif 678 } else if (isdraw) { 679 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 680 } else if (ispython) { 681 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv)); 682 } else if (isglvis) { 683 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 684 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 685 PetscCall(VecView_GLVis(locv, viewer)); 686 } else if (iscgns) { 687 #if defined(PETSC_HAVE_CGNS) 688 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 689 #else 690 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 691 #endif 692 } 693 if (fem) { 694 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 695 PetscCall(DMRestoreLocalVector(dm, &locv)); 696 } 697 } else { 698 PetscBool isseq; 699 700 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 701 if (isseq) PetscCall(VecView_Seq(v, viewer)); 702 else PetscCall(VecView_MPI(v, viewer)); 703 } 704 PetscFunctionReturn(PETSC_SUCCESS); 705 } 706 707 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 708 { 709 DM dm; 710 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython; 711 712 PetscFunctionBegin; 713 PetscCall(VecGetDM(v, &dm)); 714 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 715 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 716 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 721 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 722 if (isvtk || isdraw || isglvis || iscgns || ispython) { 723 Vec locv; 724 PetscObject isZero; 725 const char *name; 726 727 PetscCall(DMGetLocalVector(dm, &locv)); 728 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 729 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 730 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 731 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 732 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 733 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 734 PetscCall(VecView_Plex_Local(locv, viewer)); 735 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 736 PetscCall(DMRestoreLocalVector(dm, &locv)); 737 } else if (ishdf5) { 738 #if defined(PETSC_HAVE_HDF5) 739 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 740 #else 741 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 742 #endif 743 } else if (isexodusii) { 744 #if defined(PETSC_HAVE_EXODUSII) 745 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 746 #else 747 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 748 #endif 749 } else { 750 PetscBool isseq; 751 752 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 753 if (isseq) PetscCall(VecView_Seq(v, viewer)); 754 else PetscCall(VecView_MPI(v, viewer)); 755 } 756 PetscFunctionReturn(PETSC_SUCCESS); 757 } 758 759 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 760 { 761 DM dm; 762 MPI_Comm comm; 763 PetscViewerFormat format; 764 Vec v; 765 PetscBool isvtk, ishdf5; 766 767 PetscFunctionBegin; 768 PetscCall(VecGetDM(originalv, &dm)); 769 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 770 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 771 PetscCall(PetscViewerGetFormat(viewer, &format)); 772 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 773 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 774 if (format == PETSC_VIEWER_NATIVE) { 775 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 776 /* this need a better fix */ 777 if (dm->useNatural) { 778 const char *vecname; 779 PetscInt n, nroots; 780 781 PetscCheck(dm->sfNatural, comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 782 PetscCall(VecGetLocalSize(originalv, &n)); 783 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 784 PetscCheck(n == nroots, comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 785 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 786 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 787 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 788 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 789 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 790 } else v = originalv; 791 } else v = originalv; 792 793 if (ishdf5) { 794 #if defined(PETSC_HAVE_HDF5) 795 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 796 #else 797 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 798 #endif 799 } else if (isvtk) { 800 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 801 } else { 802 PetscBool isseq; 803 804 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 805 if (isseq) PetscCall(VecView_Seq(v, viewer)); 806 else PetscCall(VecView_MPI(v, viewer)); 807 } 808 if (v != originalv) PetscCall(VecDestroy(&v)); 809 PetscFunctionReturn(PETSC_SUCCESS); 810 } 811 812 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 813 { 814 DM dm; 815 PetscBool ishdf5; 816 817 PetscFunctionBegin; 818 PetscCall(VecGetDM(v, &dm)); 819 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 820 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 821 if (ishdf5) { 822 DM dmBC; 823 Vec gv; 824 const char *name; 825 826 PetscCall(DMGetOutputDM(dm, &dmBC)); 827 PetscCall(DMGetGlobalVector(dmBC, &gv)); 828 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 829 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 830 PetscCall(VecLoad_Default(gv, viewer)); 831 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 832 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 833 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 834 } else PetscCall(VecLoad_Default(v, viewer)); 835 PetscFunctionReturn(PETSC_SUCCESS); 836 } 837 838 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 839 { 840 DM dm; 841 PetscBool ishdf5, isexodusii, iscgns; 842 843 PetscFunctionBegin; 844 PetscCall(VecGetDM(v, &dm)); 845 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 846 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 847 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 848 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 849 if (ishdf5) { 850 #if defined(PETSC_HAVE_HDF5) 851 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 852 #else 853 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 854 #endif 855 } else if (isexodusii) { 856 #if defined(PETSC_HAVE_EXODUSII) 857 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 858 #else 859 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 860 #endif 861 } else if (iscgns) { 862 #if defined(PETSC_HAVE_CGNS) 863 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 864 #else 865 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 866 #endif 867 } else PetscCall(VecLoad_Default(v, viewer)); 868 PetscFunctionReturn(PETSC_SUCCESS); 869 } 870 871 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 872 { 873 DM dm; 874 PetscViewerFormat format; 875 PetscBool ishdf5; 876 877 PetscFunctionBegin; 878 PetscCall(VecGetDM(originalv, &dm)); 879 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 880 PetscCall(PetscViewerGetFormat(viewer, &format)); 881 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 882 if (format == PETSC_VIEWER_NATIVE) { 883 if (dm->useNatural) { 884 if (dm->sfNatural) { 885 if (ishdf5) { 886 #if defined(PETSC_HAVE_HDF5) 887 Vec v; 888 const char *vecname; 889 890 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 891 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 892 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 893 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 894 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 895 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 896 PetscCall(VecDestroy(&v)); 897 #else 898 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 899 #endif 900 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 901 } 902 } else PetscCall(VecLoad_Default(originalv, viewer)); 903 } 904 PetscFunctionReturn(PETSC_SUCCESS); 905 } 906 907 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 908 { 909 PetscSection coordSection; 910 Vec coordinates; 911 DMLabel depthLabel, celltypeLabel; 912 const char *name[4]; 913 const PetscScalar *a; 914 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 915 916 PetscFunctionBegin; 917 PetscCall(DMGetDimension(dm, &dim)); 918 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 919 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 920 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 921 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 922 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 923 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 924 PetscCall(VecGetArrayRead(coordinates, &a)); 925 name[0] = "vertex"; 926 name[1] = "edge"; 927 name[dim - 1] = "face"; 928 name[dim] = "cell"; 929 for (c = cStart; c < cEnd; ++c) { 930 PetscInt *closure = NULL; 931 PetscInt closureSize, cl, ct; 932 933 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 934 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 935 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 936 PetscCall(PetscViewerASCIIPushTab(viewer)); 937 for (cl = 0; cl < closureSize * 2; cl += 2) { 938 PetscInt point = closure[cl], depth, dof, off, d, p; 939 940 if ((point < pStart) || (point >= pEnd)) continue; 941 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 942 if (!dof) continue; 943 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 944 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 945 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 946 for (p = 0; p < dof / dim; ++p) { 947 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 948 for (d = 0; d < dim; ++d) { 949 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 950 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 951 } 952 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 953 } 954 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 955 } 956 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 957 PetscCall(PetscViewerASCIIPopTab(viewer)); 958 } 959 PetscCall(VecRestoreArrayRead(coordinates, &a)); 960 PetscFunctionReturn(PETSC_SUCCESS); 961 } 962 963 typedef enum { 964 CS_CARTESIAN, 965 CS_POLAR, 966 CS_CYLINDRICAL, 967 CS_SPHERICAL 968 } CoordSystem; 969 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 970 971 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 972 { 973 PetscInt i; 974 975 PetscFunctionBegin; 976 if (dim > 3) { 977 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 978 } else { 979 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 980 981 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 982 switch (cs) { 983 case CS_CARTESIAN: 984 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 985 break; 986 case CS_POLAR: 987 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 988 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 989 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 990 break; 991 case CS_CYLINDRICAL: 992 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 993 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 994 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 995 trcoords[2] = coords[2]; 996 break; 997 case CS_SPHERICAL: 998 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 999 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 1000 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 1001 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 1002 break; 1003 } 1004 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 1005 } 1006 PetscFunctionReturn(PETSC_SUCCESS); 1007 } 1008 1009 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 1010 { 1011 DM_Plex *mesh = (DM_Plex *)dm->data; 1012 DM cdm, cdmCell; 1013 PetscSection coordSection, coordSectionCell; 1014 Vec coordinates, coordinatesCell; 1015 PetscViewerFormat format; 1016 1017 PetscFunctionBegin; 1018 PetscCall(PetscViewerGetFormat(viewer, &format)); 1019 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1020 const char *name; 1021 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1022 PetscInt pStart, pEnd, p, numLabels, l; 1023 PetscMPIInt rank, size; 1024 1025 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1026 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1027 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1028 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1029 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1030 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1031 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1032 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1033 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1034 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1035 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1036 PetscCall(DMGetDimension(dm, &dim)); 1037 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1038 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1039 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1040 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1041 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1042 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1043 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1044 for (p = pStart; p < pEnd; ++p) { 1045 PetscInt dof, off, s; 1046 1047 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1048 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1049 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1050 } 1051 PetscCall(PetscViewerFlush(viewer)); 1052 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1053 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1054 for (p = pStart; p < pEnd; ++p) { 1055 PetscInt dof, off, c; 1056 1057 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1058 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1059 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 1060 } 1061 PetscCall(PetscViewerFlush(viewer)); 1062 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1063 if (coordSection && coordinates) { 1064 CoordSystem cs = CS_CARTESIAN; 1065 const PetscScalar *array, *arrayCell = NULL; 1066 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1067 PetscMPIInt rank; 1068 const char *name; 1069 1070 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1071 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1072 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1073 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1074 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1075 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1076 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1077 pStart = PetscMin(pvStart, pcStart); 1078 pEnd = PetscMax(pvEnd, pcEnd); 1079 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1080 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1081 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1082 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1083 1084 PetscCall(VecGetArrayRead(coordinates, &array)); 1085 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1086 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1087 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1088 for (p = pStart; p < pEnd; ++p) { 1089 PetscInt dof, off; 1090 1091 if (p >= pvStart && p < pvEnd) { 1092 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1093 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1094 if (dof) { 1095 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1096 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1097 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1098 } 1099 } 1100 if (cdmCell && p >= pcStart && p < pcEnd) { 1101 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1102 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1103 if (dof) { 1104 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1105 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1106 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1107 } 1108 } 1109 } 1110 PetscCall(PetscViewerFlush(viewer)); 1111 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1112 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1113 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1114 } 1115 PetscCall(DMGetNumLabels(dm, &numLabels)); 1116 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1117 for (l = 0; l < numLabels; ++l) { 1118 DMLabel label; 1119 PetscBool isdepth; 1120 const char *name; 1121 1122 PetscCall(DMGetLabelName(dm, l, &name)); 1123 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1124 if (isdepth) continue; 1125 PetscCall(DMGetLabel(dm, name, &label)); 1126 PetscCall(DMLabelView(label, viewer)); 1127 } 1128 if (size > 1) { 1129 PetscSF sf; 1130 1131 PetscCall(DMGetPointSF(dm, &sf)); 1132 PetscCall(PetscSFView(sf, viewer)); 1133 } 1134 if (mesh->periodic.face_sfs) 1135 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1136 PetscCall(PetscViewerFlush(viewer)); 1137 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1138 const char *name, *color; 1139 const char *defcolors[3] = {"gray", "orange", "green"}; 1140 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1141 char lname[PETSC_MAX_PATH_LEN]; 1142 PetscReal scale = 2.0; 1143 PetscReal tikzscale = 1.0; 1144 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1145 double tcoords[3]; 1146 PetscScalar *coords; 1147 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 1148 PetscMPIInt rank, size; 1149 char **names, **colors, **lcolors; 1150 PetscBool flg, lflg; 1151 PetscBT wp = NULL; 1152 PetscInt pEnd, pStart; 1153 1154 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1155 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1156 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1157 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1158 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1159 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1160 PetscCall(DMGetDimension(dm, &dim)); 1161 PetscCall(DMPlexGetDepth(dm, &depth)); 1162 PetscCall(DMGetNumLabels(dm, &numLabels)); 1163 numLabels = PetscMax(numLabels, 10); 1164 numColors = 10; 1165 numLColors = 10; 1166 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1167 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1168 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1169 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1170 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1171 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1172 n = 4; 1173 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1174 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1175 n = 4; 1176 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1177 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1178 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1179 if (!useLabels) numLabels = 0; 1180 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1181 if (!useColors) { 1182 numColors = 3; 1183 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1184 } 1185 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1186 if (!useColors) { 1187 numLColors = 4; 1188 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1189 } 1190 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1191 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1192 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1193 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1194 if (depth < dim) plotEdges = PETSC_FALSE; 1195 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1196 1197 /* filter points with labelvalue != labeldefaultvalue */ 1198 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1199 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1200 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1201 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1202 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1203 if (lflg) { 1204 DMLabel lbl; 1205 1206 PetscCall(DMGetLabel(dm, lname, &lbl)); 1207 if (lbl) { 1208 PetscInt val, defval; 1209 1210 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1211 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1212 for (c = pStart; c < pEnd; c++) { 1213 PetscInt *closure = NULL; 1214 PetscInt closureSize; 1215 1216 PetscCall(DMLabelGetValue(lbl, c, &val)); 1217 if (val == defval) continue; 1218 1219 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1220 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1221 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1222 } 1223 } 1224 } 1225 1226 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1227 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1228 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1229 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1230 \\documentclass[tikz]{standalone}\n\n\ 1231 \\usepackage{pgflibraryshapes}\n\ 1232 \\usetikzlibrary{backgrounds}\n\ 1233 \\usetikzlibrary{arrows}\n\ 1234 \\begin{document}\n")); 1235 if (size > 1) { 1236 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1237 for (p = 0; p < size; ++p) { 1238 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1239 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1240 } 1241 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1242 } 1243 if (drawHasse) { 1244 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1245 1246 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1249 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1258 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1262 } 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1264 1265 /* Plot vertices */ 1266 PetscCall(VecGetArray(coordinates, &coords)); 1267 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1268 for (v = vStart; v < vEnd; ++v) { 1269 PetscInt off, dof, d; 1270 PetscBool isLabeled = PETSC_FALSE; 1271 1272 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1273 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1274 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1275 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1276 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1277 for (d = 0; d < dof; ++d) { 1278 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1279 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1280 } 1281 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1282 if (dim == 3) { 1283 PetscReal tmp = tcoords[1]; 1284 tcoords[1] = tcoords[2]; 1285 tcoords[2] = -tmp; 1286 } 1287 for (d = 0; d < dof; ++d) { 1288 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1289 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1290 } 1291 if (drawHasse) color = colors[0 % numColors]; 1292 else color = colors[rank % numColors]; 1293 for (l = 0; l < numLabels; ++l) { 1294 PetscInt val; 1295 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1296 if (val >= 0) { 1297 color = lcolors[l % numLColors]; 1298 isLabeled = PETSC_TRUE; 1299 break; 1300 } 1301 } 1302 if (drawNumbers[0]) { 1303 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1304 } else if (drawColors[0]) { 1305 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1306 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1307 } 1308 PetscCall(VecRestoreArray(coordinates, &coords)); 1309 PetscCall(PetscViewerFlush(viewer)); 1310 /* Plot edges */ 1311 if (plotEdges) { 1312 PetscCall(VecGetArray(coordinates, &coords)); 1313 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1314 for (e = eStart; e < eEnd; ++e) { 1315 const PetscInt *cone; 1316 PetscInt coneSize, offA, offB, dof, d; 1317 1318 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1319 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1320 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1321 PetscCall(DMPlexGetCone(dm, e, &cone)); 1322 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1323 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1324 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1325 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1326 for (d = 0; d < dof; ++d) { 1327 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1328 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1329 } 1330 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1331 if (dim == 3) { 1332 PetscReal tmp = tcoords[1]; 1333 tcoords[1] = tcoords[2]; 1334 tcoords[2] = -tmp; 1335 } 1336 for (d = 0; d < dof; ++d) { 1337 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1338 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1339 } 1340 if (drawHasse) color = colors[1 % numColors]; 1341 else color = colors[rank % numColors]; 1342 for (l = 0; l < numLabels; ++l) { 1343 PetscInt val; 1344 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1345 if (val >= 0) { 1346 color = lcolors[l % numLColors]; 1347 break; 1348 } 1349 } 1350 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1351 } 1352 PetscCall(VecRestoreArray(coordinates, &coords)); 1353 PetscCall(PetscViewerFlush(viewer)); 1354 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1355 } 1356 /* Plot cells */ 1357 if (dim == 3 || !drawNumbers[1]) { 1358 for (e = eStart; e < eEnd; ++e) { 1359 const PetscInt *cone; 1360 1361 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1362 color = colors[rank % numColors]; 1363 for (l = 0; l < numLabels; ++l) { 1364 PetscInt val; 1365 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1366 if (val >= 0) { 1367 color = lcolors[l % numLColors]; 1368 break; 1369 } 1370 } 1371 PetscCall(DMPlexGetCone(dm, e, &cone)); 1372 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1373 } 1374 } else { 1375 DMPolytopeType ct; 1376 1377 /* Drawing a 2D polygon */ 1378 for (c = cStart; c < cEnd; ++c) { 1379 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1380 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1381 if (DMPolytopeTypeIsHybrid(ct)) { 1382 const PetscInt *cone; 1383 PetscInt coneSize, e; 1384 1385 PetscCall(DMPlexGetCone(dm, c, &cone)); 1386 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1387 for (e = 0; e < coneSize; ++e) { 1388 const PetscInt *econe; 1389 1390 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1391 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1392 } 1393 } else { 1394 PetscInt *closure = NULL; 1395 PetscInt closureSize, Nv = 0, v; 1396 1397 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1398 for (p = 0; p < closureSize * 2; p += 2) { 1399 const PetscInt point = closure[p]; 1400 1401 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1402 } 1403 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1404 for (v = 0; v <= Nv; ++v) { 1405 const PetscInt vertex = closure[v % Nv]; 1406 1407 if (v > 0) { 1408 if (plotEdges) { 1409 const PetscInt *edge; 1410 PetscInt endpoints[2], ne; 1411 1412 endpoints[0] = closure[v - 1]; 1413 endpoints[1] = vertex; 1414 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1415 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1416 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1417 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1418 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1419 } 1420 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1421 } 1422 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1423 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1424 } 1425 } 1426 } 1427 for (c = cStart; c < cEnd; ++c) { 1428 double ccoords[3] = {0.0, 0.0, 0.0}; 1429 PetscBool isLabeled = PETSC_FALSE; 1430 PetscScalar *cellCoords = NULL; 1431 const PetscScalar *array; 1432 PetscInt numCoords, cdim, d; 1433 PetscBool isDG; 1434 1435 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1436 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1437 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1438 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1439 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1440 for (p = 0; p < numCoords / cdim; ++p) { 1441 for (d = 0; d < cdim; ++d) { 1442 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1443 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1444 } 1445 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1446 if (cdim == 3) { 1447 PetscReal tmp = tcoords[1]; 1448 tcoords[1] = tcoords[2]; 1449 tcoords[2] = -tmp; 1450 } 1451 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1452 } 1453 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1454 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1455 for (d = 0; d < cdim; ++d) { 1456 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1457 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1458 } 1459 if (drawHasse) color = colors[depth % numColors]; 1460 else color = colors[rank % numColors]; 1461 for (l = 0; l < numLabels; ++l) { 1462 PetscInt val; 1463 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1464 if (val >= 0) { 1465 color = lcolors[l % numLColors]; 1466 isLabeled = PETSC_TRUE; 1467 break; 1468 } 1469 } 1470 if (drawNumbers[dim]) { 1471 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1472 } else if (drawColors[dim]) { 1473 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1474 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1475 } 1476 if (drawHasse) { 1477 int height = 0; 1478 1479 color = colors[depth % numColors]; 1480 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1481 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1482 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1483 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1484 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1485 1486 if (depth > 2) { 1487 color = colors[1 % numColors]; 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1489 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1490 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1491 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1492 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1493 } 1494 1495 color = colors[1 % numColors]; 1496 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1497 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1498 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1499 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1500 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1501 1502 color = colors[0 % numColors]; 1503 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1504 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1505 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1506 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1507 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1508 1509 for (p = pStart; p < pEnd; ++p) { 1510 const PetscInt *cone; 1511 PetscInt coneSize, cp; 1512 1513 PetscCall(DMPlexGetCone(dm, p, &cone)); 1514 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1515 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1516 } 1517 } 1518 PetscCall(PetscViewerFlush(viewer)); 1519 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1520 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1521 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1522 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1523 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1524 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1525 PetscCall(PetscFree3(names, colors, lcolors)); 1526 PetscCall(PetscBTDestroy(&wp)); 1527 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1528 Vec cown, acown; 1529 VecScatter sct; 1530 ISLocalToGlobalMapping g2l; 1531 IS gid, acis; 1532 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1533 MPI_Group ggroup, ngroup; 1534 PetscScalar *array, nid; 1535 const PetscInt *idxs; 1536 PetscInt *idxs2, *start, *adjacency, *work; 1537 PetscInt64 lm[3], gm[3]; 1538 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1539 PetscMPIInt d1, d2, rank; 1540 1541 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1542 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1543 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1544 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1545 #endif 1546 if (ncomm != MPI_COMM_NULL) { 1547 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1548 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1549 d1 = 0; 1550 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1551 nid = d2; 1552 PetscCallMPI(MPI_Group_free(&ggroup)); 1553 PetscCallMPI(MPI_Group_free(&ngroup)); 1554 PetscCallMPI(MPI_Comm_free(&ncomm)); 1555 } else nid = 0.0; 1556 1557 /* Get connectivity */ 1558 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1559 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1560 1561 /* filter overlapped local cells */ 1562 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1563 PetscCall(ISGetIndices(gid, &idxs)); 1564 PetscCall(ISGetLocalSize(gid, &cum)); 1565 PetscCall(PetscMalloc1(cum, &idxs2)); 1566 for (c = cStart, cum = 0; c < cEnd; c++) { 1567 if (idxs[c - cStart] < 0) continue; 1568 idxs2[cum++] = idxs[c - cStart]; 1569 } 1570 PetscCall(ISRestoreIndices(gid, &idxs)); 1571 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1572 PetscCall(ISDestroy(&gid)); 1573 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1574 1575 /* support for node-aware cell locality */ 1576 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1577 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1578 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1579 PetscCall(VecGetArray(cown, &array)); 1580 for (c = 0; c < numVertices; c++) array[c] = nid; 1581 PetscCall(VecRestoreArray(cown, &array)); 1582 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1583 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1584 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1585 PetscCall(ISDestroy(&acis)); 1586 PetscCall(VecScatterDestroy(&sct)); 1587 PetscCall(VecDestroy(&cown)); 1588 1589 /* compute edgeCut */ 1590 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1591 PetscCall(PetscMalloc1(cum, &work)); 1592 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1593 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1594 PetscCall(ISDestroy(&gid)); 1595 PetscCall(VecGetArray(acown, &array)); 1596 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1597 PetscInt totl; 1598 1599 totl = start[c + 1] - start[c]; 1600 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1601 for (i = 0; i < totl; i++) { 1602 if (work[i] < 0) { 1603 ect += 1; 1604 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1605 } 1606 } 1607 } 1608 PetscCall(PetscFree(work)); 1609 PetscCall(VecRestoreArray(acown, &array)); 1610 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1611 lm[1] = -numVertices; 1612 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1613 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1614 lm[0] = ect; /* edgeCut */ 1615 lm[1] = ectn; /* node-aware edgeCut */ 1616 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1617 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1618 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1619 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1620 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1621 #else 1622 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1623 #endif 1624 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1625 PetscCall(PetscFree(start)); 1626 PetscCall(PetscFree(adjacency)); 1627 PetscCall(VecDestroy(&acown)); 1628 } else { 1629 const char *name; 1630 PetscInt *sizes, *hybsizes, *ghostsizes; 1631 PetscInt locDepth, depth, cellHeight, dim, d; 1632 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1633 PetscInt numLabels, l, maxSize = 17; 1634 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1635 MPI_Comm comm; 1636 PetscMPIInt size, rank; 1637 1638 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1639 PetscCallMPI(MPI_Comm_size(comm, &size)); 1640 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1641 PetscCall(DMGetDimension(dm, &dim)); 1642 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1643 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1644 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1645 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1646 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1647 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1648 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1649 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1650 gcNum = gcEnd - gcStart; 1651 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1652 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1653 for (d = 0; d <= depth; d++) { 1654 PetscInt Nc[2] = {0, 0}, ict; 1655 1656 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1657 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1658 ict = ct0; 1659 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1660 ct0 = (DMPolytopeType)ict; 1661 for (p = pStart; p < pEnd; ++p) { 1662 DMPolytopeType ct; 1663 1664 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1665 if (ct == ct0) ++Nc[0]; 1666 else ++Nc[1]; 1667 } 1668 if (size < maxSize) { 1669 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1670 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1671 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1672 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1673 for (p = 0; p < size; ++p) { 1674 if (rank == 0) { 1675 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1676 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1677 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1678 } 1679 } 1680 } else { 1681 PetscInt locMinMax[2]; 1682 1683 locMinMax[0] = Nc[0] + Nc[1]; 1684 locMinMax[1] = Nc[0] + Nc[1]; 1685 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1686 locMinMax[0] = Nc[1]; 1687 locMinMax[1] = Nc[1]; 1688 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1689 if (d == depth) { 1690 locMinMax[0] = gcNum; 1691 locMinMax[1] = gcNum; 1692 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1693 } 1694 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1695 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1696 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1697 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1698 } 1699 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1700 } 1701 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1702 { 1703 const PetscReal *maxCell; 1704 const PetscReal *L; 1705 PetscBool localized; 1706 1707 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1708 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1709 if (L || localized) { 1710 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1711 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1712 if (L) { 1713 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1714 for (d = 0; d < dim; ++d) { 1715 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1716 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1717 } 1718 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1719 } 1720 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1721 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1722 } 1723 } 1724 PetscCall(DMGetNumLabels(dm, &numLabels)); 1725 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1726 for (l = 0; l < numLabels; ++l) { 1727 DMLabel label; 1728 const char *name; 1729 PetscInt *values; 1730 PetscInt numValues, v; 1731 1732 PetscCall(DMGetLabelName(dm, l, &name)); 1733 PetscCall(DMGetLabel(dm, name, &label)); 1734 PetscCall(DMLabelGetNumValues(label, &numValues)); 1735 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1736 1737 { // Extract array of DMLabel values so it can be sorted 1738 IS is_values; 1739 const PetscInt *is_values_local = NULL; 1740 1741 PetscCall(DMLabelGetValueIS(label, &is_values)); 1742 PetscCall(ISGetIndices(is_values, &is_values_local)); 1743 PetscCall(PetscMalloc1(numValues, &values)); 1744 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1745 PetscCall(PetscSortInt(numValues, values)); 1746 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1747 PetscCall(ISDestroy(&is_values)); 1748 } 1749 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1750 for (v = 0; v < numValues; ++v) { 1751 PetscInt size; 1752 1753 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1754 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1755 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1756 } 1757 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1758 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1759 PetscCall(PetscFree(values)); 1760 } 1761 { 1762 char **labelNames; 1763 PetscInt Nl = numLabels; 1764 PetscBool flg; 1765 1766 PetscCall(PetscMalloc1(Nl, &labelNames)); 1767 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1768 for (l = 0; l < Nl; ++l) { 1769 DMLabel label; 1770 1771 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1772 if (flg) { 1773 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1774 PetscCall(DMLabelView(label, viewer)); 1775 } 1776 PetscCall(PetscFree(labelNames[l])); 1777 } 1778 PetscCall(PetscFree(labelNames)); 1779 } 1780 /* If no fields are specified, people do not want to see adjacency */ 1781 if (dm->Nf) { 1782 PetscInt f; 1783 1784 for (f = 0; f < dm->Nf; ++f) { 1785 const char *name; 1786 1787 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1788 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1789 PetscCall(PetscViewerASCIIPushTab(viewer)); 1790 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1791 if (dm->fields[f].adjacency[0]) { 1792 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1793 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1794 } else { 1795 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1796 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1797 } 1798 PetscCall(PetscViewerASCIIPopTab(viewer)); 1799 } 1800 } 1801 DMPlexTransform tr; 1802 1803 PetscCall(DMPlexGetTransform(dm, &tr)); 1804 if (tr) { 1805 PetscCall(PetscViewerASCIIPushTab(viewer)); 1806 PetscCall(PetscViewerASCIIPrintf(viewer, "Created using transform:\n")); 1807 PetscCall(DMPlexTransformView(tr, viewer)); 1808 PetscCall(PetscViewerASCIIPopTab(viewer)); 1809 } 1810 PetscCall(DMGetCoarseDM(dm, &cdm)); 1811 if (cdm) { 1812 PetscCall(PetscViewerASCIIPushTab(viewer)); 1813 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1814 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1815 PetscCall(PetscViewerASCIIPopTab(viewer)); 1816 } 1817 } 1818 PetscFunctionReturn(PETSC_SUCCESS); 1819 } 1820 1821 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt lC, PetscInt cC, PetscInt cell, const PetscScalar coords[]) 1822 { 1823 DMPolytopeType ct; 1824 PetscMPIInt rank; 1825 PetscInt cdim; 1826 int lineColor, cellColor; 1827 1828 PetscFunctionBegin; 1829 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1830 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1831 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1832 lineColor = (int)(lC < 0 ? PETSC_DRAW_BLACK : lC); 1833 cellColor = (int)(cC < 0 ? PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2 : cC); 1834 switch (ct) { 1835 case DM_POLYTOPE_SEGMENT: 1836 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1837 switch (cdim) { 1838 case 1: { 1839 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1840 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1841 1842 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, lineColor)); 1843 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, lineColor)); 1844 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, lineColor)); 1845 } break; 1846 case 2: { 1847 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1848 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1849 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1850 1851 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1852 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, lineColor)); 1853 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, lineColor)); 1854 } break; 1855 default: 1856 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1857 } 1858 break; 1859 case DM_POLYTOPE_TRIANGLE: 1860 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1861 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1862 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1863 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1864 break; 1865 case DM_POLYTOPE_QUADRILATERAL: 1866 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1867 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), cellColor, cellColor, cellColor)); 1868 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1869 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1870 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor)); 1871 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1872 break; 1873 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1874 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1875 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1876 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1877 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor)); 1878 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1879 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1880 break; 1881 case DM_POLYTOPE_FV_GHOST: 1882 break; 1883 default: 1884 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1885 } 1886 PetscFunctionReturn(PETSC_SUCCESS); 1887 } 1888 1889 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1890 { 1891 PetscReal centroid[2] = {0., 0.}; 1892 PetscMPIInt rank; 1893 PetscMPIInt fillColor; 1894 1895 PetscFunctionBegin; 1896 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1897 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1898 for (PetscInt v = 0; v < Nv; ++v) { 1899 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1900 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1901 } 1902 for (PetscInt e = 0; e < Nv; ++e) { 1903 refCoords[0] = refVertices[e * 2 + 0]; 1904 refCoords[1] = refVertices[e * 2 + 1]; 1905 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1906 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1907 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1908 } 1909 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1910 for (PetscInt d = 0; d < edgeDiv; ++d) { 1911 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1912 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1913 } 1914 } 1915 PetscFunctionReturn(PETSC_SUCCESS); 1916 } 1917 1918 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1919 { 1920 DMPolytopeType ct; 1921 1922 PetscFunctionBegin; 1923 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1924 switch (ct) { 1925 case DM_POLYTOPE_TRIANGLE: { 1926 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1927 1928 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1929 } break; 1930 case DM_POLYTOPE_QUADRILATERAL: { 1931 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1932 1933 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1934 } break; 1935 default: 1936 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1937 } 1938 PetscFunctionReturn(PETSC_SUCCESS); 1939 } 1940 1941 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1942 { 1943 PetscDraw draw; 1944 DM cdm; 1945 PetscSection coordSection; 1946 Vec coordinates; 1947 PetscReal xyl[3], xyr[3]; 1948 PetscReal *refCoords, *edgeCoords; 1949 PetscBool isnull, drawAffine; 1950 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv, lineColor = PETSC_DETERMINE, cellColor = PETSC_DETERMINE; 1951 1952 PetscFunctionBegin; 1953 PetscCall(DMGetCoordinateDim(dm, &dim)); 1954 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1955 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1956 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1957 edgeDiv = cDegree + 1; 1958 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_line_color", &lineColor, NULL)); 1959 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_cell_color", &cellColor, NULL)); 1960 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1961 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1962 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1963 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1964 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1965 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1966 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1967 1968 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1969 PetscCall(PetscDrawIsNull(draw, &isnull)); 1970 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1971 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1972 1973 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1974 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1975 PetscCall(PetscDrawClear(draw)); 1976 1977 for (c = cStart; c < cEnd; ++c) { 1978 PetscScalar *coords = NULL; 1979 const PetscScalar *coords_arr; 1980 PetscInt numCoords; 1981 PetscBool isDG; 1982 1983 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1984 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, lineColor, cellColor, c, coords)); 1985 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1986 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1987 } 1988 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1989 PetscCall(PetscDrawFlush(draw)); 1990 PetscCall(PetscDrawPause(draw)); 1991 PetscCall(PetscDrawSave(draw)); 1992 PetscFunctionReturn(PETSC_SUCCESS); 1993 } 1994 1995 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1996 { 1997 DM odm = dm, rdm = dm, cdm; 1998 PetscFE fe; 1999 PetscSpace sp; 2000 PetscClassId id; 2001 PetscInt degree; 2002 PetscBool hoView = PETSC_TRUE; 2003 2004 PetscFunctionBegin; 2005 PetscObjectOptionsBegin((PetscObject)dm); 2006 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 2007 PetscOptionsEnd(); 2008 PetscCall(PetscObjectReference((PetscObject)dm)); 2009 *hdm = dm; 2010 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 2011 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2012 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 2013 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 2014 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 2015 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 2016 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 2017 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 2018 DM cdm, rcdm; 2019 Mat In; 2020 Vec cl, rcl; 2021 2022 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 2023 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, PETSC_FALSE)); 2024 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 2025 PetscCall(DMGetCoordinateDM(odm, &cdm)); 2026 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 2027 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 2028 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 2029 PetscCall(DMSetCoarseDM(rcdm, cdm)); 2030 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 2031 PetscCall(MatMult(In, cl, rcl)); 2032 PetscCall(MatDestroy(&In)); 2033 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 2034 PetscCall(DMDestroy(&odm)); 2035 odm = rdm; 2036 } 2037 *hdm = rdm; 2038 PetscFunctionReturn(PETSC_SUCCESS); 2039 } 2040 2041 #if defined(PETSC_HAVE_EXODUSII) 2042 #include <exodusII.h> 2043 #include <petscviewerexodusii.h> 2044 #endif 2045 2046 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 2047 { 2048 PetscBool isascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 2049 char name[PETSC_MAX_PATH_LEN]; 2050 2051 PetscFunctionBegin; 2052 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2053 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2054 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 2055 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2056 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2057 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2058 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 2059 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 2060 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 2061 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2062 if (isascii) { 2063 PetscViewerFormat format; 2064 PetscCall(PetscViewerGetFormat(viewer, &format)); 2065 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 2066 else PetscCall(DMPlexView_Ascii(dm, viewer)); 2067 } else if (ishdf5) { 2068 #if defined(PETSC_HAVE_HDF5) 2069 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 2070 #else 2071 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2072 #endif 2073 } else if (isvtk) { 2074 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2075 } else if (isdraw) { 2076 DM hdm; 2077 2078 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2079 PetscCall(DMPlexView_Draw(hdm, viewer)); 2080 PetscCall(DMDestroy(&hdm)); 2081 } else if (isglvis) { 2082 PetscCall(DMPlexView_GLVis(dm, viewer)); 2083 #if defined(PETSC_HAVE_EXODUSII) 2084 } else if (isexodus) { 2085 /* 2086 ExodusII requires that all sets be part of exactly one cell set. 2087 If the dm does not have a "Cell Sets" label defined, we create one 2088 with ID 1, containing all cells. 2089 Note that if the Cell Sets label is defined but does not cover all cells, 2090 we may still have a problem. This should probably be checked here or in the viewer; 2091 */ 2092 PetscInt numCS; 2093 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2094 if (!numCS) { 2095 PetscInt cStart, cEnd, c; 2096 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2097 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2098 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2099 } 2100 PetscCall(DMView_PlexExodusII(dm, viewer)); 2101 #endif 2102 #if defined(PETSC_HAVE_CGNS) 2103 } else if (iscgns) { 2104 PetscCall(DMView_PlexCGNS(dm, viewer)); 2105 #endif 2106 } else if (ispython) { 2107 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2108 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2109 /* Optionally view the partition */ 2110 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2111 if (flg) { 2112 Vec ranks; 2113 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2114 PetscCall(VecView(ranks, viewer)); 2115 PetscCall(VecDestroy(&ranks)); 2116 } 2117 /* Optionally view a label */ 2118 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2119 if (flg) { 2120 DMLabel label; 2121 Vec val; 2122 2123 PetscCall(DMGetLabel(dm, name, &label)); 2124 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2125 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2126 PetscCall(VecView(val, viewer)); 2127 PetscCall(VecDestroy(&val)); 2128 } 2129 PetscFunctionReturn(PETSC_SUCCESS); 2130 } 2131 2132 /*@ 2133 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2134 2135 Collective 2136 2137 Input Parameters: 2138 + dm - The `DM` whose topology is to be saved 2139 - viewer - The `PetscViewer` to save it in 2140 2141 Level: advanced 2142 2143 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2144 @*/ 2145 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2146 { 2147 PetscBool ishdf5; 2148 2149 PetscFunctionBegin; 2150 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2151 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2152 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2153 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2154 if (ishdf5) { 2155 #if defined(PETSC_HAVE_HDF5) 2156 IS globalPointNumbering; 2157 PetscViewerFormat format; 2158 2159 PetscCall(PetscViewerGetFormat(viewer, &format)); 2160 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2161 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2162 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2163 PetscCall(ISDestroy(&globalPointNumbering)); 2164 #else 2165 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2166 #endif 2167 } 2168 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2169 PetscFunctionReturn(PETSC_SUCCESS); 2170 } 2171 2172 /*@ 2173 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2174 2175 Collective 2176 2177 Input Parameters: 2178 + dm - The `DM` whose coordinates are to be saved 2179 - viewer - The `PetscViewer` for saving 2180 2181 Level: advanced 2182 2183 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2184 @*/ 2185 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2186 { 2187 PetscBool ishdf5; 2188 2189 PetscFunctionBegin; 2190 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2191 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2192 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2193 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2194 if (ishdf5) { 2195 #if defined(PETSC_HAVE_HDF5) 2196 PetscViewerFormat format; 2197 2198 PetscCall(PetscViewerGetFormat(viewer, &format)); 2199 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2200 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2201 #else 2202 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2203 #endif 2204 } 2205 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2206 PetscFunctionReturn(PETSC_SUCCESS); 2207 } 2208 2209 /*@ 2210 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2211 2212 Collective 2213 2214 Input Parameters: 2215 + dm - The `DM` whose labels are to be saved 2216 - viewer - The `PetscViewer` for saving 2217 2218 Level: advanced 2219 2220 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2221 @*/ 2222 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2223 { 2224 PetscBool ishdf5; 2225 2226 PetscFunctionBegin; 2227 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2228 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2229 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2230 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2231 if (ishdf5) { 2232 #if defined(PETSC_HAVE_HDF5) 2233 IS globalPointNumbering; 2234 PetscViewerFormat format; 2235 2236 PetscCall(PetscViewerGetFormat(viewer, &format)); 2237 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2238 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2239 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2240 PetscCall(ISDestroy(&globalPointNumbering)); 2241 #else 2242 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2243 #endif 2244 } 2245 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2246 PetscFunctionReturn(PETSC_SUCCESS); 2247 } 2248 2249 /*@ 2250 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2251 2252 Collective 2253 2254 Input Parameters: 2255 + dm - The `DM` that contains the topology on which the section to be saved is defined 2256 . viewer - The `PetscViewer` for saving 2257 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2258 2259 Level: advanced 2260 2261 Notes: 2262 This function is a wrapper around `PetscSectionView()`; in addition to the raw section, it saves information that associates the section points to the topology (`dm`) points. When the topology (`dm`) and the section are later loaded with `DMPlexTopologyLoad()` and `DMPlexSectionLoad()`, respectively, this information is used to match section points with topology points. 2263 2264 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2265 2266 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2267 @*/ 2268 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2269 { 2270 PetscBool ishdf5; 2271 2272 PetscFunctionBegin; 2273 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2274 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2275 if (!sectiondm) sectiondm = dm; 2276 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2277 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2278 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2279 if (ishdf5) { 2280 #if defined(PETSC_HAVE_HDF5) 2281 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2282 #else 2283 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2284 #endif 2285 } 2286 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2287 PetscFunctionReturn(PETSC_SUCCESS); 2288 } 2289 2290 /*@ 2291 DMPlexGlobalVectorView - Saves a global vector 2292 2293 Collective 2294 2295 Input Parameters: 2296 + dm - The `DM` that represents the topology 2297 . viewer - The `PetscViewer` to save data with 2298 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2299 - vec - The global vector to be saved 2300 2301 Level: advanced 2302 2303 Notes: 2304 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2305 2306 Calling sequence: 2307 .vb 2308 DMCreate(PETSC_COMM_WORLD, &dm); 2309 DMSetType(dm, DMPLEX); 2310 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2311 DMClone(dm, §iondm); 2312 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2313 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2314 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2315 PetscSectionSetChart(section, pStart, pEnd); 2316 PetscSectionSetUp(section); 2317 DMSetLocalSection(sectiondm, section); 2318 PetscSectionDestroy(§ion); 2319 DMGetGlobalVector(sectiondm, &vec); 2320 PetscObjectSetName((PetscObject)vec, "vec_name"); 2321 DMPlexTopologyView(dm, viewer); 2322 DMPlexSectionView(dm, viewer, sectiondm); 2323 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2324 DMRestoreGlobalVector(sectiondm, &vec); 2325 DMDestroy(§iondm); 2326 DMDestroy(&dm); 2327 .ve 2328 2329 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2330 @*/ 2331 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2332 { 2333 PetscBool ishdf5; 2334 2335 PetscFunctionBegin; 2336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2337 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2338 if (!sectiondm) sectiondm = dm; 2339 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2340 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2341 /* Check consistency */ 2342 { 2343 PetscSection section; 2344 PetscBool includesConstraints; 2345 PetscInt m, m1; 2346 2347 PetscCall(VecGetLocalSize(vec, &m1)); 2348 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2349 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2350 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2351 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2352 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2353 } 2354 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2355 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2356 if (ishdf5) { 2357 #if defined(PETSC_HAVE_HDF5) 2358 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2359 #else 2360 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2361 #endif 2362 } 2363 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2364 PetscFunctionReturn(PETSC_SUCCESS); 2365 } 2366 2367 /*@ 2368 DMPlexLocalVectorView - Saves a local vector 2369 2370 Collective 2371 2372 Input Parameters: 2373 + dm - The `DM` that represents the topology 2374 . viewer - The `PetscViewer` to save data with 2375 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2376 - vec - The local vector to be saved 2377 2378 Level: advanced 2379 2380 Note: 2381 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2382 2383 Calling sequence: 2384 .vb 2385 DMCreate(PETSC_COMM_WORLD, &dm); 2386 DMSetType(dm, DMPLEX); 2387 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2388 DMClone(dm, §iondm); 2389 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2390 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2391 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2392 PetscSectionSetChart(section, pStart, pEnd); 2393 PetscSectionSetUp(section); 2394 DMSetLocalSection(sectiondm, section); 2395 DMGetLocalVector(sectiondm, &vec); 2396 PetscObjectSetName((PetscObject)vec, "vec_name"); 2397 DMPlexTopologyView(dm, viewer); 2398 DMPlexSectionView(dm, viewer, sectiondm); 2399 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2400 DMRestoreLocalVector(sectiondm, &vec); 2401 DMDestroy(§iondm); 2402 DMDestroy(&dm); 2403 .ve 2404 2405 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2406 @*/ 2407 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2408 { 2409 PetscBool ishdf5; 2410 2411 PetscFunctionBegin; 2412 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2413 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2414 if (!sectiondm) sectiondm = dm; 2415 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2416 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2417 /* Check consistency */ 2418 { 2419 PetscSection section; 2420 PetscBool includesConstraints; 2421 PetscInt m, m1; 2422 2423 PetscCall(VecGetLocalSize(vec, &m1)); 2424 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2425 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2426 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2427 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2428 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2429 } 2430 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2431 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2432 if (ishdf5) { 2433 #if defined(PETSC_HAVE_HDF5) 2434 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2435 #else 2436 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2437 #endif 2438 } 2439 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2440 PetscFunctionReturn(PETSC_SUCCESS); 2441 } 2442 2443 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2444 { 2445 PetscBool ishdf5; 2446 2447 PetscFunctionBegin; 2448 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2449 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2450 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2451 if (ishdf5) { 2452 #if defined(PETSC_HAVE_HDF5) 2453 PetscViewerFormat format; 2454 PetscCall(PetscViewerGetFormat(viewer, &format)); 2455 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2456 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2457 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2458 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2459 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2460 PetscFunctionReturn(PETSC_SUCCESS); 2461 #else 2462 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2463 #endif 2464 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2465 } 2466 2467 /*@ 2468 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2469 2470 Collective 2471 2472 Input Parameters: 2473 + dm - The `DM` into which the topology is loaded 2474 - viewer - The `PetscViewer` for the saved topology 2475 2476 Output Parameter: 2477 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; 2478 `NULL` if unneeded 2479 2480 Level: advanced 2481 2482 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2483 `PetscViewer`, `PetscSF` 2484 @*/ 2485 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2486 { 2487 PetscBool ishdf5; 2488 2489 PetscFunctionBegin; 2490 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2491 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2492 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2493 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2494 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2495 if (ishdf5) { 2496 #if defined(PETSC_HAVE_HDF5) 2497 PetscViewerFormat format; 2498 2499 PetscCall(PetscViewerGetFormat(viewer, &format)); 2500 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2501 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2502 #else 2503 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2504 #endif 2505 } 2506 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2507 PetscFunctionReturn(PETSC_SUCCESS); 2508 } 2509 2510 /*@ 2511 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2512 2513 Collective 2514 2515 Input Parameters: 2516 + dm - The `DM` into which the coordinates are loaded 2517 . viewer - The `PetscViewer` for the saved coordinates 2518 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2519 2520 Level: advanced 2521 2522 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2523 `PetscSF`, `PetscViewer` 2524 @*/ 2525 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2526 { 2527 PetscBool ishdf5; 2528 2529 PetscFunctionBegin; 2530 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2531 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2532 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2533 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2534 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2535 if (ishdf5) { 2536 #if defined(PETSC_HAVE_HDF5) 2537 PetscViewerFormat format; 2538 2539 PetscCall(PetscViewerGetFormat(viewer, &format)); 2540 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2541 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2542 #else 2543 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2544 #endif 2545 } 2546 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2547 PetscFunctionReturn(PETSC_SUCCESS); 2548 } 2549 2550 /*@ 2551 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2552 2553 Collective 2554 2555 Input Parameters: 2556 + dm - The `DM` into which the labels are loaded 2557 . viewer - The `PetscViewer` for the saved labels 2558 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2559 2560 Level: advanced 2561 2562 Note: 2563 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2564 2565 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2566 `PetscSF`, `PetscViewer` 2567 @*/ 2568 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2569 { 2570 PetscBool ishdf5; 2571 2572 PetscFunctionBegin; 2573 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2574 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2575 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2576 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2577 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2578 if (ishdf5) { 2579 #if defined(PETSC_HAVE_HDF5) 2580 PetscViewerFormat format; 2581 2582 PetscCall(PetscViewerGetFormat(viewer, &format)); 2583 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2584 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2585 #else 2586 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2587 #endif 2588 } 2589 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2590 PetscFunctionReturn(PETSC_SUCCESS); 2591 } 2592 2593 /*@ 2594 DMPlexSectionLoad - Loads section into a `DMPLEX` 2595 2596 Collective 2597 2598 Input Parameters: 2599 + dm - The `DM` that represents the topology 2600 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2601 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2602 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2603 2604 Output Parameters: 2605 + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed) 2606 - localDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed) 2607 2608 Level: advanced 2609 2610 Notes: 2611 This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2612 2613 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2614 2615 The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2616 2617 Example using 2 processes: 2618 .vb 2619 NX (number of points on dm): 4 2620 sectionA : the on-disk section 2621 vecA : a vector associated with sectionA 2622 sectionB : sectiondm's local section constructed in this function 2623 vecB (local) : a vector associated with sectiondm's local section 2624 vecB (global) : a vector associated with sectiondm's global section 2625 2626 rank 0 rank 1 2627 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2628 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2629 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2630 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2631 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2632 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2633 sectionB->atlasDof : 1 0 1 | 1 3 2634 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2635 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2636 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2637 .ve 2638 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2639 2640 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2641 @*/ 2642 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, PeOp DM sectiondm, PetscSF globalToLocalPointSF, PeOp PetscSF *globalDofSF, PeOp PetscSF *localDofSF) 2643 { 2644 PetscBool ishdf5; 2645 2646 PetscFunctionBegin; 2647 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2648 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2649 if (!sectiondm) sectiondm = dm; 2650 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2651 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2652 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2653 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2654 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2655 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2656 if (ishdf5) { 2657 #if defined(PETSC_HAVE_HDF5) 2658 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2659 #else 2660 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2661 #endif 2662 } 2663 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2664 PetscFunctionReturn(PETSC_SUCCESS); 2665 } 2666 2667 /*@ 2668 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2669 2670 Collective 2671 2672 Input Parameters: 2673 + dm - The `DM` that represents the topology 2674 . viewer - The `PetscViewer` that represents the on-disk vector data 2675 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2676 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2677 - vec - The global vector to set values of 2678 2679 Level: advanced 2680 2681 Notes: 2682 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2683 2684 Calling sequence: 2685 .vb 2686 DMCreate(PETSC_COMM_WORLD, &dm); 2687 DMSetType(dm, DMPLEX); 2688 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2689 DMPlexTopologyLoad(dm, viewer, &sfX); 2690 DMClone(dm, §iondm); 2691 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2692 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2693 DMGetGlobalVector(sectiondm, &vec); 2694 PetscObjectSetName((PetscObject)vec, "vec_name"); 2695 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2696 DMRestoreGlobalVector(sectiondm, &vec); 2697 PetscSFDestroy(&gsf); 2698 PetscSFDestroy(&sfX); 2699 DMDestroy(§iondm); 2700 DMDestroy(&dm); 2701 .ve 2702 2703 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2704 `PetscSF`, `PetscViewer` 2705 @*/ 2706 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2707 { 2708 PetscBool ishdf5; 2709 2710 PetscFunctionBegin; 2711 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2712 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2713 if (!sectiondm) sectiondm = dm; 2714 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2715 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2716 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2717 /* Check consistency */ 2718 { 2719 PetscSection section; 2720 PetscBool includesConstraints; 2721 PetscInt m, m1; 2722 2723 PetscCall(VecGetLocalSize(vec, &m1)); 2724 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2725 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2726 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2727 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2728 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2729 } 2730 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2731 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2732 if (ishdf5) { 2733 #if defined(PETSC_HAVE_HDF5) 2734 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2735 #else 2736 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2737 #endif 2738 } 2739 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2740 PetscFunctionReturn(PETSC_SUCCESS); 2741 } 2742 2743 /*@ 2744 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2745 2746 Collective 2747 2748 Input Parameters: 2749 + dm - The `DM` that represents the topology 2750 . viewer - The `PetscViewer` that represents the on-disk vector data 2751 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2752 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2753 - vec - The local vector to set values of 2754 2755 Level: advanced 2756 2757 Notes: 2758 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2759 2760 Calling sequence: 2761 .vb 2762 DMCreate(PETSC_COMM_WORLD, &dm); 2763 DMSetType(dm, DMPLEX); 2764 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2765 DMPlexTopologyLoad(dm, viewer, &sfX); 2766 DMClone(dm, §iondm); 2767 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2768 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2769 DMGetLocalVector(sectiondm, &vec); 2770 PetscObjectSetName((PetscObject)vec, "vec_name"); 2771 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2772 DMRestoreLocalVector(sectiondm, &vec); 2773 PetscSFDestroy(&lsf); 2774 PetscSFDestroy(&sfX); 2775 DMDestroy(§iondm); 2776 DMDestroy(&dm); 2777 .ve 2778 2779 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2780 `PetscSF`, `PetscViewer` 2781 @*/ 2782 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2783 { 2784 PetscBool ishdf5; 2785 2786 PetscFunctionBegin; 2787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2788 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2789 if (!sectiondm) sectiondm = dm; 2790 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2791 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2792 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2793 /* Check consistency */ 2794 { 2795 PetscSection section; 2796 PetscBool includesConstraints; 2797 PetscInt m, m1; 2798 2799 PetscCall(VecGetLocalSize(vec, &m1)); 2800 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2801 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2802 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2803 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2804 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2805 } 2806 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2807 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2808 if (ishdf5) { 2809 #if defined(PETSC_HAVE_HDF5) 2810 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2811 #else 2812 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2813 #endif 2814 } 2815 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2816 PetscFunctionReturn(PETSC_SUCCESS); 2817 } 2818 2819 PetscErrorCode DMDestroy_Plex(DM dm) 2820 { 2821 DM_Plex *mesh = (DM_Plex *)dm->data; 2822 2823 PetscFunctionBegin; 2824 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2825 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2826 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2827 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBounds_C", NULL)); 2828 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2829 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2830 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2831 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2832 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2833 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2834 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2835 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2836 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2837 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2838 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2839 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2840 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2841 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2842 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2843 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2844 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2845 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2846 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2847 PetscCall(PetscFree(mesh->cones)); 2848 PetscCall(PetscFree(mesh->coneOrientations)); 2849 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2850 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2851 PetscCall(PetscFree(mesh->supports)); 2852 PetscCall(PetscFree(mesh->cellTypes)); 2853 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2854 PetscCall(PetscFree(mesh->tetgenOpts)); 2855 PetscCall(PetscFree(mesh->triangleOpts)); 2856 PetscCall(PetscFree(mesh->transformType)); 2857 PetscCall(PetscFree(mesh->distributionName)); 2858 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2859 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2860 PetscCall(ISDestroy(&mesh->subpointIS)); 2861 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2862 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2863 if (mesh->periodic.face_sfs) { 2864 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2865 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2866 } 2867 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2868 if (mesh->periodic.periodic_points) { 2869 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2870 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2871 } 2872 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2873 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2874 PetscCall(ISDestroy(&mesh->anchorIS)); 2875 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2876 PetscCall(PetscFree(mesh->parents)); 2877 PetscCall(PetscFree(mesh->childIDs)); 2878 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2879 PetscCall(PetscFree(mesh->children)); 2880 PetscCall(DMDestroy(&mesh->referenceTree)); 2881 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2882 PetscCall(PetscFree(mesh->neighbors)); 2883 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2884 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2885 PetscCall(DMPlexTransformDestroy(&mesh->transform)); 2886 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2887 PetscCall(PetscFree(mesh)); 2888 PetscFunctionReturn(PETSC_SUCCESS); 2889 } 2890 2891 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2892 { 2893 PetscSection sectionGlobal, sectionLocal; 2894 PetscInt bs = -1, mbs; 2895 PetscInt localSize, localStart = 0; 2896 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2897 MatType mtype; 2898 ISLocalToGlobalMapping ltog; 2899 2900 PetscFunctionBegin; 2901 PetscCall(MatInitializePackage()); 2902 mtype = dm->mattype; 2903 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2904 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2905 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2906 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2907 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2908 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2909 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2910 PetscCall(MatSetType(*J, mtype)); 2911 PetscCall(MatSetFromOptions(*J)); 2912 PetscCall(MatGetBlockSize(*J, &mbs)); 2913 if (mbs > 1) bs = mbs; 2914 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2915 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2916 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2917 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2918 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2919 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2920 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2921 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2922 if (!isShell) { 2923 // There are three states with pblocks, since block starts can have no dofs: 2924 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2925 // TRUE) Block Start: The first entry in a block has been added 2926 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2927 PetscBT blst; 2928 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2929 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2930 const PetscInt *perm = NULL; 2931 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2932 PetscInt pStart, pEnd, dof, cdof, num_fields; 2933 2934 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2935 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2936 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2937 2938 PetscCall(PetscCalloc1(localSize, &pblocks)); 2939 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2940 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2941 // We need to process in the permuted order to get block sizes right 2942 for (PetscInt point = pStart; point < pEnd; ++point) { 2943 const PetscInt p = perm ? perm[point] : point; 2944 2945 switch (dm->blocking_type) { 2946 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2947 PetscInt bdof, offset; 2948 2949 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2950 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2951 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2952 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2953 if (dof > 0) { 2954 // State change 2955 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2956 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2957 2958 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2959 // Signal block concatenation 2960 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2961 } 2962 dof = dof < 0 ? -(dof + 1) : dof; 2963 bdof = cdof && (dof - cdof) ? 1 : dof; 2964 if (dof) { 2965 if (bs < 0) { 2966 bs = bdof; 2967 } else if (bs != bdof) { 2968 bs = 1; 2969 } 2970 } 2971 } break; 2972 case DM_BLOCKING_FIELD_NODE: { 2973 for (PetscInt field = 0; field < num_fields; field++) { 2974 PetscInt num_comp, bdof, offset; 2975 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2976 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2977 if (dof < 0) continue; 2978 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2979 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2980 PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp); 2981 PetscInt num_nodes = dof / num_comp; 2982 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2983 // Handle possibly constant block size (unlikely) 2984 bdof = cdof && (dof - cdof) ? 1 : dof; 2985 if (dof) { 2986 if (bs < 0) { 2987 bs = bdof; 2988 } else if (bs != bdof) { 2989 bs = 1; 2990 } 2991 } 2992 } 2993 } break; 2994 } 2995 } 2996 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2997 /* Must have same blocksize on all procs (some might have no points) */ 2998 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 2999 bsLocal[1] = bs; 3000 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 3001 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 3002 else bs = bsMinMax[0]; 3003 bs = PetscMax(1, bs); 3004 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 3005 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 3006 PetscCall(MatSetBlockSize(*J, bs)); 3007 PetscCall(MatSetUp(*J)); 3008 } else { 3009 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 3010 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 3011 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 3012 } 3013 if (pblocks) { // Consolidate blocks 3014 PetscInt nblocks = 0; 3015 pblocks[0] = PetscAbs(pblocks[0]); 3016 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 3017 if (pblocks[i] == 0) continue; 3018 // Negative block size indicates the blocks should be concatenated 3019 if (pblocks[i] < 0) { 3020 pblocks[i] = -pblocks[i]; 3021 pblocks[nblocks - 1] += pblocks[i]; 3022 } else { 3023 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 3024 } 3025 for (PetscInt j = 1; j < pblocks[i]; j++) 3026 PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j); 3027 } 3028 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 3029 } 3030 PetscCall(PetscFree(pblocks)); 3031 } 3032 PetscCall(MatSetDM(*J, dm)); 3033 PetscFunctionReturn(PETSC_SUCCESS); 3034 } 3035 3036 /*@ 3037 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 3038 3039 Not Collective 3040 3041 Input Parameter: 3042 . dm - The `DMPLEX` 3043 3044 Output Parameter: 3045 . subsection - The subdomain section 3046 3047 Level: developer 3048 3049 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 3050 @*/ 3051 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 3052 { 3053 DM_Plex *mesh = (DM_Plex *)dm->data; 3054 3055 PetscFunctionBegin; 3056 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3057 if (!mesh->subdomainSection) { 3058 PetscSection section; 3059 PetscSF sf; 3060 3061 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 3062 PetscCall(DMGetLocalSection(dm, §ion)); 3063 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 3064 PetscCall(PetscSFDestroy(&sf)); 3065 } 3066 *subsection = mesh->subdomainSection; 3067 PetscFunctionReturn(PETSC_SUCCESS); 3068 } 3069 3070 /*@ 3071 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 3072 3073 Not Collective 3074 3075 Input Parameter: 3076 . dm - The `DMPLEX` 3077 3078 Output Parameters: 3079 + pStart - The first mesh point 3080 - pEnd - The upper bound for mesh points 3081 3082 Level: beginner 3083 3084 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3085 @*/ 3086 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3087 { 3088 DM_Plex *mesh = (DM_Plex *)dm->data; 3089 3090 PetscFunctionBegin; 3091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3092 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3093 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3094 PetscFunctionReturn(PETSC_SUCCESS); 3095 } 3096 3097 /*@ 3098 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3099 3100 Not Collective 3101 3102 Input Parameters: 3103 + dm - The `DMPLEX` 3104 . pStart - The first mesh point 3105 - pEnd - The upper bound for mesh points 3106 3107 Level: beginner 3108 3109 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3110 @*/ 3111 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3112 { 3113 DM_Plex *mesh = (DM_Plex *)dm->data; 3114 3115 PetscFunctionBegin; 3116 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3117 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3118 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3119 PetscCall(PetscFree(mesh->cellTypes)); 3120 PetscFunctionReturn(PETSC_SUCCESS); 3121 } 3122 3123 /*@ 3124 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3125 3126 Not Collective 3127 3128 Input Parameters: 3129 + dm - The `DMPLEX` 3130 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3131 3132 Output Parameter: 3133 . size - The cone size for point `p` 3134 3135 Level: beginner 3136 3137 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3138 @*/ 3139 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3140 { 3141 DM_Plex *mesh = (DM_Plex *)dm->data; 3142 3143 PetscFunctionBegin; 3144 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3145 PetscAssertPointer(size, 3); 3146 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3147 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3148 PetscFunctionReturn(PETSC_SUCCESS); 3149 } 3150 3151 /*@ 3152 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3153 3154 Not Collective 3155 3156 Input Parameters: 3157 + dm - The `DMPLEX` 3158 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3159 - size - The cone size for point `p` 3160 3161 Level: beginner 3162 3163 Note: 3164 This should be called after `DMPlexSetChart()`. 3165 3166 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3167 @*/ 3168 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3169 { 3170 DM_Plex *mesh = (DM_Plex *)dm->data; 3171 3172 PetscFunctionBegin; 3173 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3174 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3175 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3176 PetscFunctionReturn(PETSC_SUCCESS); 3177 } 3178 3179 /*@C 3180 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3181 3182 Not Collective 3183 3184 Input Parameters: 3185 + dm - The `DMPLEX` 3186 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3187 3188 Output Parameter: 3189 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3190 3191 Level: beginner 3192 3193 Fortran Notes: 3194 `cone` must be declared with 3195 .vb 3196 PetscInt, pointer :: cone(:) 3197 .ve 3198 3199 You must call `DMPlexRestoreCone()` after you finish using the array. 3200 `DMPlexRestoreCone()` is not needed/available in C. 3201 3202 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3203 @*/ 3204 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3205 { 3206 DM_Plex *mesh = (DM_Plex *)dm->data; 3207 PetscInt off; 3208 3209 PetscFunctionBegin; 3210 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3211 PetscAssertPointer(cone, 3); 3212 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3213 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3214 PetscFunctionReturn(PETSC_SUCCESS); 3215 } 3216 3217 /*@ 3218 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3219 3220 Not Collective 3221 3222 Input Parameters: 3223 + dm - The `DMPLEX` 3224 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3225 3226 Output Parameters: 3227 + pConesSection - `PetscSection` describing the layout of `pCones` 3228 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3229 3230 Level: intermediate 3231 3232 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3233 @*/ 3234 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PeOp PetscSection *pConesSection, PeOp IS *pCones) 3235 { 3236 PetscSection cs, newcs; 3237 PetscInt *cones; 3238 PetscInt *newarr = NULL; 3239 PetscInt n; 3240 3241 PetscFunctionBegin; 3242 PetscCall(DMPlexGetCones(dm, &cones)); 3243 PetscCall(DMPlexGetConeSection(dm, &cs)); 3244 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3245 if (pConesSection) *pConesSection = newcs; 3246 if (pCones) { 3247 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3248 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3249 } 3250 PetscFunctionReturn(PETSC_SUCCESS); 3251 } 3252 3253 /*@ 3254 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3255 3256 Not Collective 3257 3258 Input Parameters: 3259 + dm - The `DMPLEX` 3260 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3261 3262 Output Parameter: 3263 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3264 3265 Level: advanced 3266 3267 Notes: 3268 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3269 3270 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3271 3272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3273 `DMPlexGetDepth()`, `IS` 3274 @*/ 3275 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3276 { 3277 IS *expandedPointsAll; 3278 PetscInt depth; 3279 3280 PetscFunctionBegin; 3281 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3282 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3283 PetscAssertPointer(expandedPoints, 3); 3284 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3285 *expandedPoints = expandedPointsAll[0]; 3286 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3287 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3288 PetscFunctionReturn(PETSC_SUCCESS); 3289 } 3290 3291 /*@ 3292 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3293 (DAG points of depth 0, i.e., without cones). 3294 3295 Not Collective 3296 3297 Input Parameters: 3298 + dm - The `DMPLEX` 3299 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3300 3301 Output Parameters: 3302 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3303 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3304 - sections - (optional) An array of sections which describe mappings from points to their cone points 3305 3306 Level: advanced 3307 3308 Notes: 3309 Like `DMPlexGetConeTuple()` but recursive. 3310 3311 Array `expandedPoints` has size equal to `depth`. Each `expandedPoints`[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 3312 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3313 3314 Array section has size equal to `depth`. Each `PetscSection` `sections`[d] realizes mapping from `expandedPoints`[d+1] (section points) to `expandedPoints`[d] (section dofs) as follows\: 3315 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3316 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3317 3318 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3319 `DMPlexGetDepth()`, `PetscSection`, `IS` 3320 @*/ 3321 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3322 { 3323 const PetscInt *arr0 = NULL, *cone = NULL; 3324 PetscInt *arr = NULL, *newarr = NULL; 3325 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3326 IS *expandedPoints_; 3327 PetscSection *sections_; 3328 3329 PetscFunctionBegin; 3330 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3331 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3332 if (depth) PetscAssertPointer(depth, 3); 3333 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3334 if (sections) PetscAssertPointer(sections, 5); 3335 PetscCall(ISGetLocalSize(points, &n)); 3336 PetscCall(ISGetIndices(points, &arr0)); 3337 PetscCall(DMPlexGetDepth(dm, &depth_)); 3338 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3339 PetscCall(PetscCalloc1(depth_, §ions_)); 3340 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3341 for (d = depth_ - 1; d >= 0; d--) { 3342 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3343 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3344 for (i = 0; i < n; i++) { 3345 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3346 if (arr[i] >= start && arr[i] < end) { 3347 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3348 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3349 } else { 3350 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3351 } 3352 } 3353 PetscCall(PetscSectionSetUp(sections_[d])); 3354 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3355 PetscCall(PetscMalloc1(newn, &newarr)); 3356 for (i = 0; i < n; i++) { 3357 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3358 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3359 if (cn > 1) { 3360 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3361 PetscCall(PetscArraycpy(&newarr[co], cone, cn)); 3362 } else { 3363 newarr[co] = arr[i]; 3364 } 3365 } 3366 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3367 arr = newarr; 3368 n = newn; 3369 } 3370 PetscCall(ISRestoreIndices(points, &arr0)); 3371 *depth = depth_; 3372 if (expandedPoints) *expandedPoints = expandedPoints_; 3373 else { 3374 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3375 PetscCall(PetscFree(expandedPoints_)); 3376 } 3377 if (sections) *sections = sections_; 3378 else { 3379 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3380 PetscCall(PetscFree(sections_)); 3381 } 3382 PetscFunctionReturn(PETSC_SUCCESS); 3383 } 3384 3385 /*@ 3386 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3387 3388 Not Collective 3389 3390 Input Parameters: 3391 + dm - The `DMPLEX` 3392 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3393 3394 Output Parameters: 3395 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3396 . expandedPoints - (optional) An array of recursively expanded cones 3397 - sections - (optional) An array of sections which describe mappings from points to their cone points 3398 3399 Level: advanced 3400 3401 Note: 3402 See `DMPlexGetConeRecursive()` 3403 3404 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3405 `DMPlexGetDepth()`, `IS`, `PetscSection` 3406 @*/ 3407 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3408 { 3409 PetscInt d, depth_; 3410 3411 PetscFunctionBegin; 3412 PetscCall(DMPlexGetDepth(dm, &depth_)); 3413 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3414 if (depth) *depth = 0; 3415 if (expandedPoints) { 3416 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3417 PetscCall(PetscFree(*expandedPoints)); 3418 } 3419 if (sections) { 3420 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3421 PetscCall(PetscFree(*sections)); 3422 } 3423 PetscFunctionReturn(PETSC_SUCCESS); 3424 } 3425 3426 /*@ 3427 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 3428 3429 Not Collective 3430 3431 Input Parameters: 3432 + dm - The `DMPLEX` 3433 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3434 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3435 3436 Level: beginner 3437 3438 Note: 3439 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3440 3441 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3442 @*/ 3443 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3444 { 3445 DM_Plex *mesh = (DM_Plex *)dm->data; 3446 PetscInt dof, off, c; 3447 3448 PetscFunctionBegin; 3449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3450 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3451 if (dof) PetscAssertPointer(cone, 3); 3452 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3453 if (PetscDefined(USE_DEBUG)) { 3454 PetscInt pStart, pEnd; 3455 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3456 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3457 for (c = 0; c < dof; ++c) { 3458 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3459 mesh->cones[off + c] = cone[c]; 3460 } 3461 } else { 3462 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3463 } 3464 PetscFunctionReturn(PETSC_SUCCESS); 3465 } 3466 3467 /*@C 3468 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3469 3470 Not Collective 3471 3472 Input Parameters: 3473 + dm - The `DMPLEX` 3474 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3475 3476 Output Parameter: 3477 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3478 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3479 3480 Level: beginner 3481 3482 Note: 3483 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3484 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3485 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3486 with the identity. 3487 3488 Fortran Notes: 3489 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3490 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3491 3492 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3493 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3494 @*/ 3495 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3496 { 3497 DM_Plex *mesh = (DM_Plex *)dm->data; 3498 PetscInt off; 3499 3500 PetscFunctionBegin; 3501 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3502 if (PetscDefined(USE_DEBUG)) { 3503 PetscInt dof; 3504 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3505 if (dof) PetscAssertPointer(coneOrientation, 3); 3506 } 3507 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3508 3509 *coneOrientation = &mesh->coneOrientations[off]; 3510 PetscFunctionReturn(PETSC_SUCCESS); 3511 } 3512 3513 /*@ 3514 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3515 3516 Not Collective 3517 3518 Input Parameters: 3519 + dm - The `DMPLEX` 3520 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3521 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3522 3523 Level: beginner 3524 3525 Notes: 3526 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3527 3528 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3529 3530 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3531 @*/ 3532 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3533 { 3534 DM_Plex *mesh = (DM_Plex *)dm->data; 3535 PetscInt pStart, pEnd; 3536 PetscInt dof, off, c; 3537 3538 PetscFunctionBegin; 3539 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3540 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3541 if (dof) PetscAssertPointer(coneOrientation, 3); 3542 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3543 if (PetscDefined(USE_DEBUG)) { 3544 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3545 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3546 for (c = 0; c < dof; ++c) { 3547 PetscInt cdof, o = coneOrientation[c]; 3548 3549 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3550 PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof); 3551 mesh->coneOrientations[off + c] = o; 3552 } 3553 } else { 3554 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3555 } 3556 PetscFunctionReturn(PETSC_SUCCESS); 3557 } 3558 3559 /*@ 3560 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3561 3562 Not Collective 3563 3564 Input Parameters: 3565 + dm - The `DMPLEX` 3566 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3567 . conePos - The local index in the cone where the point should be put 3568 - conePoint - The mesh point to insert 3569 3570 Level: beginner 3571 3572 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3573 @*/ 3574 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3575 { 3576 DM_Plex *mesh = (DM_Plex *)dm->data; 3577 PetscInt pStart, pEnd; 3578 PetscInt dof, off; 3579 3580 PetscFunctionBegin; 3581 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3582 if (PetscDefined(USE_DEBUG)) { 3583 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3584 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3585 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3586 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3587 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3588 } 3589 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3590 mesh->cones[off + conePos] = conePoint; 3591 PetscFunctionReturn(PETSC_SUCCESS); 3592 } 3593 3594 /*@ 3595 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3596 3597 Not Collective 3598 3599 Input Parameters: 3600 + dm - The `DMPLEX` 3601 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3602 . conePos - The local index in the cone where the point should be put 3603 - coneOrientation - The point orientation to insert 3604 3605 Level: beginner 3606 3607 Note: 3608 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3609 3610 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3611 @*/ 3612 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3613 { 3614 DM_Plex *mesh = (DM_Plex *)dm->data; 3615 PetscInt pStart, pEnd; 3616 PetscInt dof, off; 3617 3618 PetscFunctionBegin; 3619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3620 if (PetscDefined(USE_DEBUG)) { 3621 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3622 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3623 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3624 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3625 } 3626 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3627 mesh->coneOrientations[off + conePos] = coneOrientation; 3628 PetscFunctionReturn(PETSC_SUCCESS); 3629 } 3630 3631 /*@C 3632 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3633 3634 Not collective 3635 3636 Input Parameters: 3637 + dm - The DMPlex 3638 - p - The point, which must lie in the chart set with DMPlexSetChart() 3639 3640 Output Parameters: 3641 + cone - An array of points which are on the in-edges for point `p` 3642 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3643 integer giving the prescription for cone traversal. 3644 3645 Level: beginner 3646 3647 Notes: 3648 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3649 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3650 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3651 with the identity. 3652 3653 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3654 3655 Fortran Notes: 3656 `cone` and `ornt` must be declared with 3657 .vb 3658 PetscInt, pointer :: cone(:) 3659 PetscInt, pointer :: ornt(:) 3660 .ve 3661 3662 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3663 @*/ 3664 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, PeOp const PetscInt *cone[], PeOp const PetscInt *ornt[]) 3665 { 3666 DM_Plex *mesh = (DM_Plex *)dm->data; 3667 3668 PetscFunctionBegin; 3669 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3670 if (mesh->tr) { 3671 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3672 } else { 3673 PetscInt off; 3674 if (PetscDefined(USE_DEBUG)) { 3675 PetscInt dof; 3676 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3677 if (dof) { 3678 if (cone) PetscAssertPointer(cone, 3); 3679 if (ornt) PetscAssertPointer(ornt, 4); 3680 } 3681 } 3682 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3683 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3684 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3685 } 3686 PetscFunctionReturn(PETSC_SUCCESS); 3687 } 3688 3689 /*@C 3690 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3691 3692 Not Collective 3693 3694 Input Parameters: 3695 + dm - The DMPlex 3696 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3697 . cone - An array of points which are on the in-edges for point p 3698 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3699 integer giving the prescription for cone traversal. 3700 3701 Level: beginner 3702 3703 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3704 @*/ 3705 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3706 { 3707 DM_Plex *mesh = (DM_Plex *)dm->data; 3708 3709 PetscFunctionBegin; 3710 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3711 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3712 PetscFunctionReturn(PETSC_SUCCESS); 3713 } 3714 3715 /*@ 3716 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3717 3718 Not Collective 3719 3720 Input Parameters: 3721 + dm - The `DMPLEX` 3722 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3723 3724 Output Parameter: 3725 . size - The support size for point `p` 3726 3727 Level: beginner 3728 3729 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3730 @*/ 3731 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3732 { 3733 DM_Plex *mesh = (DM_Plex *)dm->data; 3734 3735 PetscFunctionBegin; 3736 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3737 PetscAssertPointer(size, 3); 3738 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3739 PetscFunctionReturn(PETSC_SUCCESS); 3740 } 3741 3742 /*@ 3743 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3744 3745 Not Collective 3746 3747 Input Parameters: 3748 + dm - The `DMPLEX` 3749 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3750 - size - The support size for point `p` 3751 3752 Level: beginner 3753 3754 Note: 3755 This should be called after `DMPlexSetChart()`. 3756 3757 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3758 @*/ 3759 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3760 { 3761 DM_Plex *mesh = (DM_Plex *)dm->data; 3762 3763 PetscFunctionBegin; 3764 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3765 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3766 PetscFunctionReturn(PETSC_SUCCESS); 3767 } 3768 3769 /*@C 3770 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3771 3772 Not Collective 3773 3774 Input Parameters: 3775 + dm - The `DMPLEX` 3776 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3777 3778 Output Parameter: 3779 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3780 3781 Level: beginner 3782 3783 Fortran Notes: 3784 `support` must be declared with 3785 .vb 3786 PetscInt, pointer :: support(:) 3787 .ve 3788 3789 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3790 `DMPlexRestoreSupport()` is not needed/available in C. 3791 3792 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3793 @*/ 3794 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3795 { 3796 DM_Plex *mesh = (DM_Plex *)dm->data; 3797 PetscInt off; 3798 3799 PetscFunctionBegin; 3800 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3801 PetscAssertPointer(support, 3); 3802 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3803 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3804 PetscFunctionReturn(PETSC_SUCCESS); 3805 } 3806 3807 /*@ 3808 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3809 3810 Not Collective 3811 3812 Input Parameters: 3813 + dm - The `DMPLEX` 3814 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3815 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3816 3817 Level: beginner 3818 3819 Note: 3820 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3821 3822 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3823 @*/ 3824 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3825 { 3826 DM_Plex *mesh = (DM_Plex *)dm->data; 3827 PetscInt pStart, pEnd; 3828 PetscInt dof, off, c; 3829 3830 PetscFunctionBegin; 3831 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3832 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3833 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3834 if (dof) PetscAssertPointer(support, 3); 3835 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3836 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3837 for (c = 0; c < dof; ++c) { 3838 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3839 mesh->supports[off + c] = support[c]; 3840 } 3841 PetscFunctionReturn(PETSC_SUCCESS); 3842 } 3843 3844 /*@ 3845 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3846 3847 Not Collective 3848 3849 Input Parameters: 3850 + dm - The `DMPLEX` 3851 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3852 . supportPos - The local index in the cone where the point should be put 3853 - supportPoint - The mesh point to insert 3854 3855 Level: beginner 3856 3857 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3858 @*/ 3859 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3860 { 3861 DM_Plex *mesh = (DM_Plex *)dm->data; 3862 PetscInt pStart, pEnd; 3863 PetscInt dof, off; 3864 3865 PetscFunctionBegin; 3866 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3867 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3868 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3869 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3870 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3871 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3872 PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3873 mesh->supports[off + supportPos] = supportPoint; 3874 PetscFunctionReturn(PETSC_SUCCESS); 3875 } 3876 3877 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3878 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3879 { 3880 switch (ct) { 3881 case DM_POLYTOPE_SEGMENT: 3882 if (o == -1) return -2; 3883 break; 3884 case DM_POLYTOPE_TRIANGLE: 3885 if (o == -3) return -1; 3886 if (o == -2) return -3; 3887 if (o == -1) return -2; 3888 break; 3889 case DM_POLYTOPE_QUADRILATERAL: 3890 if (o == -4) return -2; 3891 if (o == -3) return -1; 3892 if (o == -2) return -4; 3893 if (o == -1) return -3; 3894 break; 3895 default: 3896 return o; 3897 } 3898 return o; 3899 } 3900 3901 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3902 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3903 { 3904 switch (ct) { 3905 case DM_POLYTOPE_SEGMENT: 3906 if ((o == -2) || (o == 1)) return -1; 3907 if (o == -1) return 0; 3908 break; 3909 case DM_POLYTOPE_TRIANGLE: 3910 if (o == -3) return -2; 3911 if (o == -2) return -1; 3912 if (o == -1) return -3; 3913 break; 3914 case DM_POLYTOPE_QUADRILATERAL: 3915 if (o == -4) return -2; 3916 if (o == -3) return -1; 3917 if (o == -2) return -4; 3918 if (o == -1) return -3; 3919 break; 3920 default: 3921 return o; 3922 } 3923 return o; 3924 } 3925 3926 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3927 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3928 { 3929 PetscInt pStart, pEnd, p; 3930 3931 PetscFunctionBegin; 3932 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3933 for (p = pStart; p < pEnd; ++p) { 3934 const PetscInt *cone, *ornt; 3935 PetscInt coneSize, c; 3936 3937 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3938 PetscCall(DMPlexGetCone(dm, p, &cone)); 3939 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3940 for (c = 0; c < coneSize; ++c) { 3941 DMPolytopeType ct; 3942 const PetscInt o = ornt[c]; 3943 3944 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3945 switch (ct) { 3946 case DM_POLYTOPE_SEGMENT: 3947 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3948 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3949 break; 3950 case DM_POLYTOPE_TRIANGLE: 3951 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3952 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3953 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3954 break; 3955 case DM_POLYTOPE_QUADRILATERAL: 3956 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3957 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3958 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3959 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3960 break; 3961 default: 3962 break; 3963 } 3964 } 3965 } 3966 PetscFunctionReturn(PETSC_SUCCESS); 3967 } 3968 3969 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3970 { 3971 DM_Plex *mesh = (DM_Plex *)dm->data; 3972 3973 PetscFunctionBeginHot; 3974 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3975 if (useCone) { 3976 PetscCall(DMPlexGetConeSize(dm, p, size)); 3977 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3978 } else { 3979 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3980 PetscCall(DMPlexGetSupport(dm, p, arr)); 3981 } 3982 } else { 3983 if (useCone) { 3984 const PetscSection s = mesh->coneSection; 3985 const PetscInt ps = p - s->pStart; 3986 const PetscInt off = s->atlasOff[ps]; 3987 3988 *size = s->atlasDof[ps]; 3989 *arr = mesh->cones + off; 3990 *ornt = mesh->coneOrientations + off; 3991 } else { 3992 const PetscSection s = mesh->supportSection; 3993 const PetscInt ps = p - s->pStart; 3994 const PetscInt off = s->atlasOff[ps]; 3995 3996 *size = s->atlasDof[ps]; 3997 *arr = mesh->supports + off; 3998 } 3999 } 4000 PetscFunctionReturn(PETSC_SUCCESS); 4001 } 4002 4003 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 4004 { 4005 DM_Plex *mesh = (DM_Plex *)dm->data; 4006 4007 PetscFunctionBeginHot; 4008 if (PetscDefined(USE_DEBUG) || mesh->tr) { 4009 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 4010 } 4011 PetscFunctionReturn(PETSC_SUCCESS); 4012 } 4013 4014 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4015 { 4016 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4017 PetscInt *closure; 4018 const PetscInt *tmp = NULL, *tmpO = NULL; 4019 PetscInt off = 0, tmpSize, t; 4020 4021 PetscFunctionBeginHot; 4022 if (ornt) { 4023 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4024 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 4025 } 4026 if (*points) { 4027 closure = *points; 4028 } else { 4029 PetscInt maxConeSize, maxSupportSize; 4030 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4031 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 4032 } 4033 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4034 if (ct == DM_POLYTOPE_UNKNOWN) { 4035 closure[off++] = p; 4036 closure[off++] = 0; 4037 for (t = 0; t < tmpSize; ++t) { 4038 closure[off++] = tmp[t]; 4039 closure[off++] = tmpO ? tmpO[t] : 0; 4040 } 4041 } else { 4042 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 4043 4044 /* We assume that cells with a valid type have faces with a valid type */ 4045 closure[off++] = p; 4046 closure[off++] = ornt; 4047 for (t = 0; t < tmpSize; ++t) { 4048 DMPolytopeType ft; 4049 4050 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 4051 closure[off++] = tmp[arr[t]]; 4052 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 4053 } 4054 } 4055 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4056 if (numPoints) *numPoints = tmpSize + 1; 4057 if (points) *points = closure; 4058 PetscFunctionReturn(PETSC_SUCCESS); 4059 } 4060 4061 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 4062 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 4063 { 4064 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 4065 const PetscInt *cone, *ornt; 4066 PetscInt *pts, *closure = NULL; 4067 DMPolytopeType ft; 4068 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 4069 PetscInt dim, coneSize, c, d, clSize, cl; 4070 4071 PetscFunctionBeginHot; 4072 PetscCall(DMGetDimension(dm, &dim)); 4073 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4074 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4075 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4076 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4077 maxSize = PetscMax(coneSeries, supportSeries); 4078 if (*points) { 4079 pts = *points; 4080 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4081 c = 0; 4082 pts[c++] = point; 4083 pts[c++] = o; 4084 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4085 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4086 for (cl = 0; cl < clSize * 2; cl += 2) { 4087 pts[c++] = closure[cl]; 4088 pts[c++] = closure[cl + 1]; 4089 } 4090 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4091 for (cl = 0; cl < clSize * 2; cl += 2) { 4092 pts[c++] = closure[cl]; 4093 pts[c++] = closure[cl + 1]; 4094 } 4095 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4096 for (d = 2; d < coneSize; ++d) { 4097 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4098 pts[c++] = cone[arr[d * 2 + 0]]; 4099 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4100 } 4101 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4102 if (dim >= 3) { 4103 for (d = 2; d < coneSize; ++d) { 4104 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4105 const PetscInt *fcone, *fornt; 4106 PetscInt fconeSize, fc, i; 4107 4108 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4109 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4110 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4111 for (fc = 0; fc < fconeSize; ++fc) { 4112 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4113 const PetscInt co = farr[fc * 2 + 1]; 4114 4115 for (i = 0; i < c; i += 2) 4116 if (pts[i] == cp) break; 4117 if (i == c) { 4118 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4119 pts[c++] = cp; 4120 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4121 } 4122 } 4123 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4124 } 4125 } 4126 *numPoints = c / 2; 4127 *points = pts; 4128 PetscFunctionReturn(PETSC_SUCCESS); 4129 } 4130 4131 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4132 { 4133 DMPolytopeType ct; 4134 PetscInt *closure, *fifo; 4135 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4136 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4137 PetscInt depth, maxSize; 4138 4139 PetscFunctionBeginHot; 4140 PetscCall(DMPlexGetDepth(dm, &depth)); 4141 if (depth == 1) { 4142 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4143 PetscFunctionReturn(PETSC_SUCCESS); 4144 } 4145 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4146 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 4147 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4148 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4149 PetscFunctionReturn(PETSC_SUCCESS); 4150 } 4151 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4152 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4153 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4154 maxSize = PetscMax(coneSeries, supportSeries); 4155 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4156 if (*points) { 4157 closure = *points; 4158 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4159 closure[closureSize++] = p; 4160 closure[closureSize++] = ornt; 4161 fifo[fifoSize++] = p; 4162 fifo[fifoSize++] = ornt; 4163 fifo[fifoSize++] = ct; 4164 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4165 while (fifoSize - fifoStart) { 4166 const PetscInt q = fifo[fifoStart++]; 4167 const PetscInt o = fifo[fifoStart++]; 4168 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4169 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4170 const PetscInt *tmp, *tmpO = NULL; 4171 PetscInt tmpSize, t; 4172 4173 if (PetscDefined(USE_DEBUG)) { 4174 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4175 PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 4176 } 4177 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4178 for (t = 0; t < tmpSize; ++t) { 4179 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4180 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4181 const PetscInt cp = tmp[ip]; 4182 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4183 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4184 PetscInt c; 4185 4186 /* Check for duplicate */ 4187 for (c = 0; c < closureSize; c += 2) { 4188 if (closure[c] == cp) break; 4189 } 4190 if (c == closureSize) { 4191 closure[closureSize++] = cp; 4192 closure[closureSize++] = co; 4193 fifo[fifoSize++] = cp; 4194 fifo[fifoSize++] = co; 4195 fifo[fifoSize++] = ct; 4196 } 4197 } 4198 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4199 } 4200 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4201 if (numPoints) *numPoints = closureSize / 2; 4202 if (points) *points = closure; 4203 PetscFunctionReturn(PETSC_SUCCESS); 4204 } 4205 4206 /*@C 4207 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4208 4209 Not Collective 4210 4211 Input Parameters: 4212 + dm - The `DMPLEX` 4213 . p - The mesh point 4214 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4215 4216 Input/Output Parameter: 4217 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4218 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4219 otherwise the provided array is used to hold the values 4220 4221 Output Parameter: 4222 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4223 4224 Level: beginner 4225 4226 Note: 4227 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4228 4229 Fortran Notes: 4230 `points` must be declared with 4231 .vb 4232 PetscInt, pointer :: points(:) 4233 .ve 4234 and is always allocated by the function. 4235 4236 Pass `PETSC_NULL_INTEGER` for `numPoints` if it is not needed 4237 4238 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4239 @*/ 4240 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4241 { 4242 PetscFunctionBeginHot; 4243 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4244 if (numPoints) PetscAssertPointer(numPoints, 4); 4245 if (points) PetscAssertPointer(points, 5); 4246 if (PetscDefined(USE_DEBUG)) { 4247 PetscInt pStart, pEnd; 4248 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4249 PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 4250 } 4251 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4252 PetscFunctionReturn(PETSC_SUCCESS); 4253 } 4254 4255 /*@C 4256 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4257 4258 Not Collective 4259 4260 Input Parameters: 4261 + dm - The `DMPLEX` 4262 . p - The mesh point 4263 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4264 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4265 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4266 4267 Level: beginner 4268 4269 Note: 4270 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4271 4272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4273 @*/ 4274 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4275 { 4276 PetscFunctionBeginHot; 4277 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4278 if (numPoints) *numPoints = 0; 4279 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4280 PetscFunctionReturn(PETSC_SUCCESS); 4281 } 4282 4283 /*@ 4284 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4285 4286 Not Collective 4287 4288 Input Parameter: 4289 . dm - The `DMPLEX` 4290 4291 Output Parameters: 4292 + maxConeSize - The maximum number of in-edges 4293 - maxSupportSize - The maximum number of out-edges 4294 4295 Level: beginner 4296 4297 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4298 @*/ 4299 PetscErrorCode DMPlexGetMaxSizes(DM dm, PeOp PetscInt *maxConeSize, PeOp PetscInt *maxSupportSize) 4300 { 4301 DM_Plex *mesh = (DM_Plex *)dm->data; 4302 4303 PetscFunctionBegin; 4304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4305 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4306 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4307 PetscFunctionReturn(PETSC_SUCCESS); 4308 } 4309 4310 PetscErrorCode DMSetUp_Plex(DM dm) 4311 { 4312 DM_Plex *mesh = (DM_Plex *)dm->data; 4313 PetscInt size, maxSupportSize; 4314 4315 PetscFunctionBegin; 4316 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4317 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4318 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4319 PetscCall(PetscMalloc1(size, &mesh->cones)); 4320 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4321 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4322 if (maxSupportSize) { 4323 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4324 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4325 PetscCall(PetscMalloc1(size, &mesh->supports)); 4326 } 4327 PetscFunctionReturn(PETSC_SUCCESS); 4328 } 4329 4330 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4331 { 4332 PetscFunctionBegin; 4333 if (subdm) PetscCall(DMClone(dm, subdm)); 4334 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4335 if (subdm) (*subdm)->useNatural = dm->useNatural; 4336 if (dm->useNatural && dm->sfMigration) { 4337 PetscSF sfNatural; 4338 4339 (*subdm)->sfMigration = dm->sfMigration; 4340 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4341 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4342 (*subdm)->sfNatural = sfNatural; 4343 } 4344 PetscFunctionReturn(PETSC_SUCCESS); 4345 } 4346 4347 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4348 { 4349 PetscInt i = 0; 4350 4351 PetscFunctionBegin; 4352 PetscCall(DMClone(dms[0], superdm)); 4353 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4354 (*superdm)->useNatural = PETSC_FALSE; 4355 for (i = 0; i < len; i++) { 4356 if (dms[i]->useNatural && dms[i]->sfMigration) { 4357 PetscSF sfNatural; 4358 4359 (*superdm)->sfMigration = dms[i]->sfMigration; 4360 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4361 (*superdm)->useNatural = PETSC_TRUE; 4362 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4363 (*superdm)->sfNatural = sfNatural; 4364 break; 4365 } 4366 } 4367 PetscFunctionReturn(PETSC_SUCCESS); 4368 } 4369 4370 /*@ 4371 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4372 4373 Not Collective 4374 4375 Input Parameter: 4376 . dm - The `DMPLEX` 4377 4378 Level: beginner 4379 4380 Note: 4381 This should be called after all calls to `DMPlexSetCone()` 4382 4383 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4384 @*/ 4385 PetscErrorCode DMPlexSymmetrize(DM dm) 4386 { 4387 DM_Plex *mesh = (DM_Plex *)dm->data; 4388 PetscInt *offsets; 4389 PetscInt supportSize; 4390 PetscInt pStart, pEnd, p; 4391 4392 PetscFunctionBegin; 4393 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4394 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4395 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4396 /* Calculate support sizes */ 4397 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4398 for (p = pStart; p < pEnd; ++p) { 4399 PetscInt dof, off, c; 4400 4401 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4402 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4403 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4404 } 4405 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4406 /* Calculate supports */ 4407 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4408 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4409 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4410 for (p = pStart; p < pEnd; ++p) { 4411 PetscInt dof, off, c; 4412 4413 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4414 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4415 for (c = off; c < off + dof; ++c) { 4416 const PetscInt q = mesh->cones[c]; 4417 PetscInt offS; 4418 4419 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4420 4421 mesh->supports[offS + offsets[q]] = p; 4422 ++offsets[q]; 4423 } 4424 } 4425 PetscCall(PetscFree(offsets)); 4426 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4427 PetscFunctionReturn(PETSC_SUCCESS); 4428 } 4429 4430 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4431 { 4432 IS stratumIS; 4433 4434 PetscFunctionBegin; 4435 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4436 if (PetscDefined(USE_DEBUG)) { 4437 PetscInt qStart, qEnd, numLevels, level; 4438 PetscBool overlap = PETSC_FALSE; 4439 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4440 for (level = 0; level < numLevels; level++) { 4441 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4442 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4443 overlap = PETSC_TRUE; 4444 break; 4445 } 4446 } 4447 PetscCheck(!overlap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd); 4448 } 4449 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4450 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4451 PetscCall(ISDestroy(&stratumIS)); 4452 PetscFunctionReturn(PETSC_SUCCESS); 4453 } 4454 4455 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4456 { 4457 PetscInt *pMin, *pMax; 4458 PetscInt pStart, pEnd; 4459 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4460 4461 PetscFunctionBegin; 4462 { 4463 DMLabel label2; 4464 4465 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4466 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4467 } 4468 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4469 for (PetscInt p = pStart; p < pEnd; ++p) { 4470 DMPolytopeType ct; 4471 4472 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4473 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4474 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4475 } 4476 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4477 for (PetscInt d = dmin; d <= dmax; ++d) { 4478 pMin[d] = PETSC_INT_MAX; 4479 pMax[d] = PETSC_INT_MIN; 4480 } 4481 for (PetscInt p = pStart; p < pEnd; ++p) { 4482 DMPolytopeType ct; 4483 PetscInt d; 4484 4485 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4486 d = DMPolytopeTypeGetDim(ct); 4487 pMin[d] = PetscMin(p, pMin[d]); 4488 pMax[d] = PetscMax(p, pMax[d]); 4489 } 4490 for (PetscInt d = dmin; d <= dmax; ++d) { 4491 if (pMin[d] > pMax[d]) continue; 4492 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4493 } 4494 PetscCall(PetscFree2(pMin, pMax)); 4495 PetscFunctionReturn(PETSC_SUCCESS); 4496 } 4497 4498 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4499 { 4500 PetscInt pStart, pEnd; 4501 PetscInt numRoots = 0, numLeaves = 0; 4502 4503 PetscFunctionBegin; 4504 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4505 { 4506 /* Initialize roots and count leaves */ 4507 PetscInt sMin = PETSC_INT_MAX; 4508 PetscInt sMax = PETSC_INT_MIN; 4509 PetscInt coneSize, supportSize; 4510 4511 for (PetscInt p = pStart; p < pEnd; ++p) { 4512 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4513 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4514 if (!coneSize && supportSize) { 4515 sMin = PetscMin(p, sMin); 4516 sMax = PetscMax(p, sMax); 4517 ++numRoots; 4518 } else if (!supportSize && coneSize) { 4519 ++numLeaves; 4520 } else if (!supportSize && !coneSize) { 4521 /* Isolated points */ 4522 sMin = PetscMin(p, sMin); 4523 sMax = PetscMax(p, sMax); 4524 } 4525 } 4526 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4527 } 4528 4529 if (numRoots + numLeaves == (pEnd - pStart)) { 4530 PetscInt sMin = PETSC_INT_MAX; 4531 PetscInt sMax = PETSC_INT_MIN; 4532 PetscInt coneSize, supportSize; 4533 4534 for (PetscInt p = pStart; p < pEnd; ++p) { 4535 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4536 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4537 if (!supportSize && coneSize) { 4538 sMin = PetscMin(p, sMin); 4539 sMax = PetscMax(p, sMax); 4540 } 4541 } 4542 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4543 } else { 4544 PetscInt level = 0; 4545 PetscInt qStart, qEnd; 4546 4547 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4548 while (qEnd > qStart) { 4549 PetscInt sMin = PETSC_INT_MAX; 4550 PetscInt sMax = PETSC_INT_MIN; 4551 4552 for (PetscInt q = qStart; q < qEnd; ++q) { 4553 const PetscInt *support; 4554 PetscInt supportSize; 4555 4556 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4557 PetscCall(DMPlexGetSupport(dm, q, &support)); 4558 for (PetscInt s = 0; s < supportSize; ++s) { 4559 sMin = PetscMin(support[s], sMin); 4560 sMax = PetscMax(support[s], sMax); 4561 } 4562 } 4563 PetscCall(DMLabelGetNumValues(label, &level)); 4564 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4565 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4566 } 4567 } 4568 PetscFunctionReturn(PETSC_SUCCESS); 4569 } 4570 4571 /*@ 4572 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4573 4574 Collective 4575 4576 Input Parameter: 4577 . dm - The `DMPLEX` 4578 4579 Level: beginner 4580 4581 Notes: 4582 The strata group all points of the same grade, and this function calculates the strata. This 4583 grade can be seen as the height (or depth) of the point in the DAG. 4584 4585 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4586 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4587 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4588 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4589 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4590 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4591 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4592 4593 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4594 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4595 we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose 4596 to interpolate only that one (e0), so that 4597 .vb 4598 cone(c0) = {e0, v2} 4599 cone(e0) = {v0, v1} 4600 .ve 4601 If `DMPlexStratify()` is run on this mesh, it will give depths 4602 .vb 4603 depth 0 = {v0, v1, v2} 4604 depth 1 = {e0, c0} 4605 .ve 4606 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4607 4608 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4609 4610 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4611 @*/ 4612 PetscErrorCode DMPlexStratify(DM dm) 4613 { 4614 DM_Plex *mesh = (DM_Plex *)dm->data; 4615 DMLabel label; 4616 PetscBool flg = PETSC_FALSE; 4617 4618 PetscFunctionBegin; 4619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4620 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4621 4622 // Create depth label 4623 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4624 PetscCall(DMCreateLabel(dm, "depth")); 4625 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4626 4627 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4628 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4629 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4630 4631 { /* just in case there is an empty process */ 4632 PetscInt numValues, maxValues = 0, v; 4633 4634 PetscCall(DMLabelGetNumValues(label, &numValues)); 4635 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4636 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4637 } 4638 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4639 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4640 PetscFunctionReturn(PETSC_SUCCESS); 4641 } 4642 4643 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4644 { 4645 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4646 PetscInt dim, depth, pheight, coneSize; 4647 PetscBool preferTensor; 4648 4649 PetscFunctionBeginHot; 4650 PetscCall(DMGetDimension(dm, &dim)); 4651 PetscCall(DMPlexGetDepth(dm, &depth)); 4652 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4653 PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor)); 4654 pheight = depth - pdepth; 4655 if (depth <= 1) { 4656 switch (pdepth) { 4657 case 0: 4658 ct = DM_POLYTOPE_POINT; 4659 break; 4660 case 1: 4661 switch (coneSize) { 4662 case 2: 4663 ct = DM_POLYTOPE_SEGMENT; 4664 break; 4665 case 3: 4666 ct = DM_POLYTOPE_TRIANGLE; 4667 break; 4668 case 4: 4669 switch (dim) { 4670 case 2: 4671 ct = DM_POLYTOPE_QUADRILATERAL; 4672 break; 4673 case 3: 4674 ct = DM_POLYTOPE_TETRAHEDRON; 4675 break; 4676 default: 4677 break; 4678 } 4679 break; 4680 case 5: 4681 ct = DM_POLYTOPE_PYRAMID; 4682 break; 4683 case 6: 4684 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4685 break; 4686 case 8: 4687 ct = DM_POLYTOPE_HEXAHEDRON; 4688 break; 4689 default: 4690 break; 4691 } 4692 } 4693 } else { 4694 if (pdepth == 0) { 4695 ct = DM_POLYTOPE_POINT; 4696 } else if (pheight == 0) { 4697 switch (dim) { 4698 case 1: 4699 switch (coneSize) { 4700 case 2: 4701 ct = DM_POLYTOPE_SEGMENT; 4702 break; 4703 default: 4704 break; 4705 } 4706 break; 4707 case 2: 4708 switch (coneSize) { 4709 case 3: 4710 ct = DM_POLYTOPE_TRIANGLE; 4711 break; 4712 case 4: 4713 ct = DM_POLYTOPE_QUADRILATERAL; 4714 break; 4715 default: 4716 break; 4717 } 4718 break; 4719 case 3: 4720 switch (coneSize) { 4721 case 4: 4722 ct = DM_POLYTOPE_TETRAHEDRON; 4723 break; 4724 case 5: { 4725 const PetscInt *cone; 4726 PetscInt faceConeSize; 4727 4728 PetscCall(DMPlexGetCone(dm, p, &cone)); 4729 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4730 switch (faceConeSize) { 4731 case 3: 4732 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4733 break; 4734 case 4: 4735 ct = DM_POLYTOPE_PYRAMID; 4736 break; 4737 } 4738 } break; 4739 case 6: 4740 ct = DM_POLYTOPE_HEXAHEDRON; 4741 break; 4742 default: 4743 break; 4744 } 4745 break; 4746 default: 4747 break; 4748 } 4749 } else if (pheight > 0) { 4750 switch (coneSize) { 4751 case 2: 4752 ct = DM_POLYTOPE_SEGMENT; 4753 break; 4754 case 3: 4755 ct = DM_POLYTOPE_TRIANGLE; 4756 break; 4757 case 4: 4758 ct = DM_POLYTOPE_QUADRILATERAL; 4759 break; 4760 default: 4761 break; 4762 } 4763 } 4764 } 4765 *pt = ct; 4766 PetscFunctionReturn(PETSC_SUCCESS); 4767 } 4768 4769 /*@ 4770 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4771 4772 Collective 4773 4774 Input Parameter: 4775 . dm - The `DMPLEX` 4776 4777 Level: developer 4778 4779 Note: 4780 This function is normally called automatically when a cell type is requested. It creates an 4781 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4782 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4783 4784 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4785 4786 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4787 @*/ 4788 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4789 { 4790 DM_Plex *mesh; 4791 DMLabel ctLabel; 4792 PetscInt pStart, pEnd, p; 4793 4794 PetscFunctionBegin; 4795 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4796 mesh = (DM_Plex *)dm->data; 4797 PetscCall(DMCreateLabel(dm, "celltype")); 4798 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4799 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4800 PetscCall(PetscFree(mesh->cellTypes)); 4801 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4802 for (p = pStart; p < pEnd; ++p) { 4803 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4804 PetscInt pdepth; 4805 4806 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4807 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4808 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]); 4809 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4810 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4811 } 4812 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4813 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4814 PetscFunctionReturn(PETSC_SUCCESS); 4815 } 4816 4817 /*@C 4818 DMPlexGetJoin - Get an array for the join of the set of points 4819 4820 Not Collective 4821 4822 Input Parameters: 4823 + dm - The `DMPLEX` object 4824 . numPoints - The number of input points for the join 4825 - points - The input points 4826 4827 Output Parameters: 4828 + numCoveredPoints - The number of points in the join 4829 - coveredPoints - The points in the join 4830 4831 Level: intermediate 4832 4833 Note: 4834 Currently, this is restricted to a single level join 4835 4836 Fortran Notes: 4837 `converedPoints` must be declared with 4838 .vb 4839 PetscInt, pointer :: coveredPints(:) 4840 .ve 4841 4842 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4843 @*/ 4844 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4845 { 4846 DM_Plex *mesh = (DM_Plex *)dm->data; 4847 PetscInt *join[2]; 4848 PetscInt joinSize, i = 0; 4849 PetscInt dof, off, p, c, m; 4850 PetscInt maxSupportSize; 4851 4852 PetscFunctionBegin; 4853 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4854 PetscAssertPointer(points, 3); 4855 PetscAssertPointer(numCoveredPoints, 4); 4856 PetscAssertPointer(coveredPoints, 5); 4857 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4858 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4859 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4860 /* Copy in support of first point */ 4861 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4862 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4863 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4864 /* Check each successive support */ 4865 for (p = 1; p < numPoints; ++p) { 4866 PetscInt newJoinSize = 0; 4867 4868 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4869 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4870 for (c = 0; c < dof; ++c) { 4871 const PetscInt point = mesh->supports[off + c]; 4872 4873 for (m = 0; m < joinSize; ++m) { 4874 if (point == join[i][m]) { 4875 join[1 - i][newJoinSize++] = point; 4876 break; 4877 } 4878 } 4879 } 4880 joinSize = newJoinSize; 4881 i = 1 - i; 4882 } 4883 *numCoveredPoints = joinSize; 4884 *coveredPoints = join[i]; 4885 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4886 PetscFunctionReturn(PETSC_SUCCESS); 4887 } 4888 4889 /*@C 4890 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4891 4892 Not Collective 4893 4894 Input Parameters: 4895 + dm - The `DMPLEX` object 4896 . numPoints - The number of input points for the join 4897 - points - The input points 4898 4899 Output Parameters: 4900 + numCoveredPoints - The number of points in the join 4901 - coveredPoints - The points in the join 4902 4903 Level: intermediate 4904 4905 Fortran Notes: 4906 `converedPoints` must be declared with 4907 .vb 4908 PetscInt, pointer :: coveredPoints(:) 4909 .ve 4910 4911 Pass `PETSC_NULL_INTEGER` for `numCoveredPoints` if it is not needed 4912 4913 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4914 @*/ 4915 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4916 { 4917 PetscFunctionBegin; 4918 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4919 if (points) PetscAssertPointer(points, 3); 4920 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4921 PetscAssertPointer(coveredPoints, 5); 4922 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4923 if (numCoveredPoints) *numCoveredPoints = 0; 4924 PetscFunctionReturn(PETSC_SUCCESS); 4925 } 4926 4927 /*@C 4928 DMPlexGetFullJoin - Get an array for the join of the set of points 4929 4930 Not Collective 4931 4932 Input Parameters: 4933 + dm - The `DMPLEX` object 4934 . numPoints - The number of input points for the join 4935 - points - The input points, its length is `numPoints` 4936 4937 Output Parameters: 4938 + numCoveredPoints - The number of points in the join 4939 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4940 4941 Level: intermediate 4942 4943 Fortran Notes: 4944 .vb 4945 PetscInt, pointer :: coveredPints(:) 4946 .ve 4947 4948 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4949 @*/ 4950 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4951 { 4952 PetscInt *offsets, **closures; 4953 PetscInt *join[2]; 4954 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4955 PetscInt p, d, c, m, ms; 4956 4957 PetscFunctionBegin; 4958 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4959 PetscAssertPointer(points, 3); 4960 PetscAssertPointer(numCoveredPoints, 4); 4961 PetscAssertPointer(coveredPoints, 5); 4962 4963 PetscCall(DMPlexGetDepth(dm, &depth)); 4964 PetscCall(PetscCalloc1(numPoints, &closures)); 4965 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4966 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4967 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4968 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4969 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4970 4971 for (p = 0; p < numPoints; ++p) { 4972 PetscInt closureSize; 4973 4974 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4975 4976 offsets[p * (depth + 2) + 0] = 0; 4977 for (d = 0; d < depth + 1; ++d) { 4978 PetscInt pStart, pEnd, i; 4979 4980 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4981 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4982 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4983 offsets[p * (depth + 2) + d + 1] = i; 4984 break; 4985 } 4986 } 4987 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4988 } 4989 PetscCheck(offsets[p * (depth + 2) + depth + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (depth + 2) + depth + 1], closureSize); 4990 } 4991 for (d = 0; d < depth + 1; ++d) { 4992 PetscInt dof; 4993 4994 /* Copy in support of first point */ 4995 dof = offsets[d + 1] - offsets[d]; 4996 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4997 /* Check each successive cone */ 4998 for (p = 1; p < numPoints && joinSize; ++p) { 4999 PetscInt newJoinSize = 0; 5000 5001 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 5002 for (c = 0; c < dof; ++c) { 5003 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 5004 5005 for (m = 0; m < joinSize; ++m) { 5006 if (point == join[i][m]) { 5007 join[1 - i][newJoinSize++] = point; 5008 break; 5009 } 5010 } 5011 } 5012 joinSize = newJoinSize; 5013 i = 1 - i; 5014 } 5015 if (joinSize) break; 5016 } 5017 *numCoveredPoints = joinSize; 5018 *coveredPoints = join[i]; 5019 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 5020 PetscCall(PetscFree(closures)); 5021 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 5022 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 5023 PetscFunctionReturn(PETSC_SUCCESS); 5024 } 5025 5026 /*@C 5027 DMPlexGetMeet - Get an array for the meet of the set of points 5028 5029 Not Collective 5030 5031 Input Parameters: 5032 + dm - The `DMPLEX` object 5033 . numPoints - The number of input points for the meet 5034 - points - The input points, of length `numPoints` 5035 5036 Output Parameters: 5037 + numCoveringPoints - The number of points in the meet 5038 - coveringPoints - The points in the meet, of length `numCoveringPoints` 5039 5040 Level: intermediate 5041 5042 Note: 5043 Currently, this is restricted to a single level meet 5044 5045 Fortran Note: 5046 `coveringPoints` must be declared with 5047 .vb 5048 PetscInt, pointer :: coveringPoints(:) 5049 .ve 5050 5051 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5052 @*/ 5053 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 5054 { 5055 DM_Plex *mesh = (DM_Plex *)dm->data; 5056 PetscInt *meet[2]; 5057 PetscInt meetSize, i = 0; 5058 PetscInt dof, off, p, c, m; 5059 PetscInt maxConeSize; 5060 5061 PetscFunctionBegin; 5062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5063 PetscAssertPointer(points, 3); 5064 PetscAssertPointer(numCoveringPoints, 4); 5065 PetscAssertPointer(coveringPoints, 5); 5066 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 5067 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 5068 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 5069 /* Copy in cone of first point */ 5070 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 5071 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 5072 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5073 /* Check each successive cone */ 5074 for (p = 1; p < numPoints; ++p) { 5075 PetscInt newMeetSize = 0; 5076 5077 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5078 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5079 for (c = 0; c < dof; ++c) { 5080 const PetscInt point = mesh->cones[off + c]; 5081 5082 for (m = 0; m < meetSize; ++m) { 5083 if (point == meet[i][m]) { 5084 meet[1 - i][newMeetSize++] = point; 5085 break; 5086 } 5087 } 5088 } 5089 meetSize = newMeetSize; 5090 i = 1 - i; 5091 } 5092 *numCoveringPoints = meetSize; 5093 *coveringPoints = meet[i]; 5094 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5095 PetscFunctionReturn(PETSC_SUCCESS); 5096 } 5097 5098 /*@C 5099 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5100 5101 Not Collective 5102 5103 Input Parameters: 5104 + dm - The `DMPLEX` object 5105 . numPoints - The number of input points for the meet 5106 - points - The input points 5107 5108 Output Parameters: 5109 + numCoveredPoints - The number of points in the meet 5110 - coveredPoints - The points in the meet 5111 5112 Level: intermediate 5113 5114 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5115 @*/ 5116 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5117 { 5118 PetscFunctionBegin; 5119 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5120 if (points) PetscAssertPointer(points, 3); 5121 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5122 PetscAssertPointer(coveredPoints, 5); 5123 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5124 if (numCoveredPoints) *numCoveredPoints = 0; 5125 PetscFunctionReturn(PETSC_SUCCESS); 5126 } 5127 5128 /*@C 5129 DMPlexGetFullMeet - Get an array for the meet of the set of points 5130 5131 Not Collective 5132 5133 Input Parameters: 5134 + dm - The `DMPLEX` object 5135 . numPoints - The number of input points for the meet 5136 - points - The input points, of length `numPoints` 5137 5138 Output Parameters: 5139 + numCoveredPoints - The number of points in the meet 5140 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5141 5142 Level: intermediate 5143 5144 Fortran Notes: 5145 `coveredPoints` must be declared with 5146 .vb 5147 PetscInt, pointer :: coveredPoints(:) 5148 .ve 5149 5150 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5151 @*/ 5152 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5153 { 5154 PetscInt *offsets, **closures; 5155 PetscInt *meet[2]; 5156 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5157 PetscInt p, h, c, m, mc; 5158 5159 PetscFunctionBegin; 5160 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5161 PetscAssertPointer(points, 3); 5162 PetscAssertPointer(numCoveredPoints, 4); 5163 PetscAssertPointer(coveredPoints, 5); 5164 5165 PetscCall(DMPlexGetDepth(dm, &height)); 5166 PetscCall(PetscMalloc1(numPoints, &closures)); 5167 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5168 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5169 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5170 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5171 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5172 5173 for (p = 0; p < numPoints; ++p) { 5174 PetscInt closureSize; 5175 5176 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5177 5178 offsets[p * (height + 2) + 0] = 0; 5179 for (h = 0; h < height + 1; ++h) { 5180 PetscInt pStart, pEnd, i; 5181 5182 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5183 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5184 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5185 offsets[p * (height + 2) + h + 1] = i; 5186 break; 5187 } 5188 } 5189 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5190 } 5191 PetscCheck(offsets[p * (height + 2) + height + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (height + 2) + height + 1], closureSize); 5192 } 5193 for (h = 0; h < height + 1; ++h) { 5194 PetscInt dof; 5195 5196 /* Copy in cone of first point */ 5197 dof = offsets[h + 1] - offsets[h]; 5198 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5199 /* Check each successive cone */ 5200 for (p = 1; p < numPoints && meetSize; ++p) { 5201 PetscInt newMeetSize = 0; 5202 5203 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5204 for (c = 0; c < dof; ++c) { 5205 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5206 5207 for (m = 0; m < meetSize; ++m) { 5208 if (point == meet[i][m]) { 5209 meet[1 - i][newMeetSize++] = point; 5210 break; 5211 } 5212 } 5213 } 5214 meetSize = newMeetSize; 5215 i = 1 - i; 5216 } 5217 if (meetSize) break; 5218 } 5219 *numCoveredPoints = meetSize; 5220 *coveredPoints = meet[i]; 5221 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5222 PetscCall(PetscFree(closures)); 5223 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5224 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5225 PetscFunctionReturn(PETSC_SUCCESS); 5226 } 5227 5228 /*@ 5229 DMPlexEqual - Determine if two `DM` have the same topology 5230 5231 Not Collective 5232 5233 Input Parameters: 5234 + dmA - A `DMPLEX` object 5235 - dmB - A `DMPLEX` object 5236 5237 Output Parameter: 5238 . equal - `PETSC_TRUE` if the topologies are identical 5239 5240 Level: intermediate 5241 5242 Note: 5243 We are not solving graph isomorphism, so we do not permute. 5244 5245 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5246 @*/ 5247 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5248 { 5249 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5250 5251 PetscFunctionBegin; 5252 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5253 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5254 PetscAssertPointer(equal, 3); 5255 5256 *equal = PETSC_FALSE; 5257 PetscCall(DMPlexGetDepth(dmA, &depth)); 5258 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5259 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5260 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5261 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5262 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5263 for (p = pStart; p < pEnd; ++p) { 5264 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5265 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5266 5267 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5268 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5269 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5270 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5271 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5272 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5273 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5274 for (c = 0; c < coneSize; ++c) { 5275 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5276 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5277 } 5278 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5279 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5280 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5281 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5282 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5283 for (s = 0; s < supportSize; ++s) { 5284 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5285 } 5286 } 5287 *equal = PETSC_TRUE; 5288 PetscFunctionReturn(PETSC_SUCCESS); 5289 } 5290 5291 /*@ 5292 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5293 5294 Not Collective 5295 5296 Input Parameters: 5297 + dm - The `DMPLEX` 5298 . cellDim - The cell dimension 5299 - numCorners - The number of vertices on a cell 5300 5301 Output Parameter: 5302 . numFaceVertices - The number of vertices on a face 5303 5304 Level: developer 5305 5306 Note: 5307 Of course this can only work for a restricted set of symmetric shapes 5308 5309 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5310 @*/ 5311 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5312 { 5313 MPI_Comm comm; 5314 5315 PetscFunctionBegin; 5316 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5317 PetscAssertPointer(numFaceVertices, 4); 5318 switch (cellDim) { 5319 case 0: 5320 *numFaceVertices = 0; 5321 break; 5322 case 1: 5323 *numFaceVertices = 1; 5324 break; 5325 case 2: 5326 switch (numCorners) { 5327 case 3: /* triangle */ 5328 *numFaceVertices = 2; /* Edge has 2 vertices */ 5329 break; 5330 case 4: /* quadrilateral */ 5331 *numFaceVertices = 2; /* Edge has 2 vertices */ 5332 break; 5333 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5334 *numFaceVertices = 3; /* Edge has 3 vertices */ 5335 break; 5336 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5337 *numFaceVertices = 3; /* Edge has 3 vertices */ 5338 break; 5339 default: 5340 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5341 } 5342 break; 5343 case 3: 5344 switch (numCorners) { 5345 case 4: /* tetradehdron */ 5346 *numFaceVertices = 3; /* Face has 3 vertices */ 5347 break; 5348 case 6: /* tet cohesive cells */ 5349 *numFaceVertices = 4; /* Face has 4 vertices */ 5350 break; 5351 case 8: /* hexahedron */ 5352 *numFaceVertices = 4; /* Face has 4 vertices */ 5353 break; 5354 case 9: /* tet cohesive Lagrange cells */ 5355 *numFaceVertices = 6; /* Face has 6 vertices */ 5356 break; 5357 case 10: /* quadratic tetrahedron */ 5358 *numFaceVertices = 6; /* Face has 6 vertices */ 5359 break; 5360 case 12: /* hex cohesive Lagrange cells */ 5361 *numFaceVertices = 6; /* Face has 6 vertices */ 5362 break; 5363 case 18: /* quadratic tet cohesive Lagrange cells */ 5364 *numFaceVertices = 6; /* Face has 6 vertices */ 5365 break; 5366 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5367 *numFaceVertices = 9; /* Face has 9 vertices */ 5368 break; 5369 default: 5370 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5371 } 5372 break; 5373 default: 5374 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5375 } 5376 PetscFunctionReturn(PETSC_SUCCESS); 5377 } 5378 5379 /*@ 5380 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5381 5382 Not Collective 5383 5384 Input Parameter: 5385 . dm - The `DMPLEX` object 5386 5387 Output Parameter: 5388 . depthLabel - The `DMLabel` recording point depth 5389 5390 Level: developer 5391 5392 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5393 @*/ 5394 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5395 { 5396 PetscFunctionBegin; 5397 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5398 PetscAssertPointer(depthLabel, 2); 5399 *depthLabel = dm->depthLabel; 5400 PetscFunctionReturn(PETSC_SUCCESS); 5401 } 5402 5403 /*@ 5404 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5405 5406 Not Collective 5407 5408 Input Parameter: 5409 . dm - The `DMPLEX` object 5410 5411 Output Parameter: 5412 . depth - The number of strata (breadth first levels) in the DAG 5413 5414 Level: developer 5415 5416 Notes: 5417 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5418 5419 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5420 5421 An empty mesh gives -1. 5422 5423 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5424 @*/ 5425 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5426 { 5427 DM_Plex *mesh = (DM_Plex *)dm->data; 5428 DMLabel label; 5429 PetscInt d = -1; 5430 5431 PetscFunctionBegin; 5432 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5433 PetscAssertPointer(depth, 2); 5434 if (mesh->tr) { 5435 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5436 } else { 5437 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5438 // Allow missing depths 5439 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5440 *depth = d; 5441 } 5442 PetscFunctionReturn(PETSC_SUCCESS); 5443 } 5444 5445 /*@ 5446 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5447 5448 Not Collective 5449 5450 Input Parameters: 5451 + dm - The `DMPLEX` object 5452 - depth - The requested depth 5453 5454 Output Parameters: 5455 + start - The first point at this `depth` 5456 - end - One beyond the last point at this `depth` 5457 5458 Level: developer 5459 5460 Notes: 5461 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5462 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5463 higher dimension, e.g., "edges". 5464 5465 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5466 @*/ 5467 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PeOp PetscInt *start, PeOp PetscInt *end) 5468 { 5469 DM_Plex *mesh = (DM_Plex *)dm->data; 5470 DMLabel label; 5471 PetscInt pStart, pEnd; 5472 5473 PetscFunctionBegin; 5474 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5475 if (start) { 5476 PetscAssertPointer(start, 3); 5477 *start = 0; 5478 } 5479 if (end) { 5480 PetscAssertPointer(end, 4); 5481 *end = 0; 5482 } 5483 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5484 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5485 if (depth < 0) { 5486 if (start) *start = pStart; 5487 if (end) *end = pEnd; 5488 PetscFunctionReturn(PETSC_SUCCESS); 5489 } 5490 if (mesh->tr) { 5491 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5492 } else { 5493 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5494 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5495 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5496 } 5497 PetscFunctionReturn(PETSC_SUCCESS); 5498 } 5499 5500 /*@ 5501 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5502 5503 Not Collective 5504 5505 Input Parameters: 5506 + dm - The `DMPLEX` object 5507 - height - The requested height 5508 5509 Output Parameters: 5510 + start - The first point at this `height` 5511 - end - One beyond the last point at this `height` 5512 5513 Level: developer 5514 5515 Notes: 5516 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5517 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5518 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5519 5520 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5521 @*/ 5522 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PeOp PetscInt *start, PeOp PetscInt *end) 5523 { 5524 DMLabel label; 5525 PetscInt depth, pStart, pEnd; 5526 5527 PetscFunctionBegin; 5528 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5529 if (start) { 5530 PetscAssertPointer(start, 3); 5531 *start = 0; 5532 } 5533 if (end) { 5534 PetscAssertPointer(end, 4); 5535 *end = 0; 5536 } 5537 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5538 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5539 if (height < 0) { 5540 if (start) *start = pStart; 5541 if (end) *end = pEnd; 5542 PetscFunctionReturn(PETSC_SUCCESS); 5543 } 5544 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5545 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5546 else PetscCall(DMGetDimension(dm, &depth)); 5547 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5548 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5549 PetscFunctionReturn(PETSC_SUCCESS); 5550 } 5551 5552 /*@ 5553 DMPlexGetPointDepth - Get the `depth` of a given point 5554 5555 Not Collective 5556 5557 Input Parameters: 5558 + dm - The `DMPLEX` object 5559 - point - The point 5560 5561 Output Parameter: 5562 . depth - The depth of the `point` 5563 5564 Level: intermediate 5565 5566 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5567 @*/ 5568 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5569 { 5570 PetscFunctionBegin; 5571 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5572 PetscAssertPointer(depth, 3); 5573 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5574 PetscFunctionReturn(PETSC_SUCCESS); 5575 } 5576 5577 /*@ 5578 DMPlexGetPointHeight - Get the `height` of a given point 5579 5580 Not Collective 5581 5582 Input Parameters: 5583 + dm - The `DMPLEX` object 5584 - point - The point 5585 5586 Output Parameter: 5587 . height - The height of the `point` 5588 5589 Level: intermediate 5590 5591 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5592 @*/ 5593 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5594 { 5595 PetscInt n, pDepth; 5596 5597 PetscFunctionBegin; 5598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5599 PetscAssertPointer(height, 3); 5600 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5601 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5602 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5603 PetscFunctionReturn(PETSC_SUCCESS); 5604 } 5605 5606 /*@ 5607 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5608 5609 Not Collective 5610 5611 Input Parameter: 5612 . dm - The `DMPLEX` object 5613 5614 Output Parameter: 5615 . celltypeLabel - The `DMLabel` recording cell polytope type 5616 5617 Level: developer 5618 5619 Note: 5620 This function will trigger automatica computation of cell types. This can be disabled by calling 5621 `DMCreateLabel`(dm, "celltype") beforehand. 5622 5623 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5624 @*/ 5625 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5626 { 5627 PetscFunctionBegin; 5628 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5629 PetscAssertPointer(celltypeLabel, 2); 5630 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5631 *celltypeLabel = dm->celltypeLabel; 5632 PetscFunctionReturn(PETSC_SUCCESS); 5633 } 5634 5635 /*@ 5636 DMPlexGetCellType - Get the polytope type of a given cell 5637 5638 Not Collective 5639 5640 Input Parameters: 5641 + dm - The `DMPLEX` object 5642 - cell - The cell 5643 5644 Output Parameter: 5645 . celltype - The polytope type of the cell 5646 5647 Level: intermediate 5648 5649 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5650 @*/ 5651 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5652 { 5653 DM_Plex *mesh = (DM_Plex *)dm->data; 5654 DMLabel label; 5655 PetscInt ct; 5656 5657 PetscFunctionBegin; 5658 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5659 PetscAssertPointer(celltype, 3); 5660 if (mesh->tr) { 5661 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5662 } else { 5663 PetscInt pStart, pEnd; 5664 5665 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5666 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5667 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5668 if (pEnd <= pStart) { 5669 *celltype = DM_POLYTOPE_UNKNOWN; 5670 PetscFunctionReturn(PETSC_SUCCESS); 5671 } 5672 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5673 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5674 for (PetscInt p = pStart; p < pEnd; p++) { 5675 PetscCall(DMLabelGetValue(label, p, &ct)); 5676 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5677 } 5678 } 5679 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5680 if (PetscDefined(USE_DEBUG)) { 5681 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5682 PetscCall(DMLabelGetValue(label, cell, &ct)); 5683 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5684 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5685 } 5686 } 5687 PetscFunctionReturn(PETSC_SUCCESS); 5688 } 5689 5690 /*@ 5691 DMPlexSetCellType - Set the polytope type of a given cell 5692 5693 Not Collective 5694 5695 Input Parameters: 5696 + dm - The `DMPLEX` object 5697 . cell - The cell 5698 - celltype - The polytope type of the cell 5699 5700 Level: advanced 5701 5702 Note: 5703 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5704 is executed. This function will override the computed type. However, if automatic classification will not succeed 5705 and a user wants to manually specify all types, the classification must be disabled by calling 5706 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5707 5708 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5709 @*/ 5710 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5711 { 5712 DM_Plex *mesh = (DM_Plex *)dm->data; 5713 DMLabel label; 5714 PetscInt pStart, pEnd; 5715 5716 PetscFunctionBegin; 5717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5718 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5719 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5720 PetscCall(DMLabelSetValue(label, cell, celltype)); 5721 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5722 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5723 PetscFunctionReturn(PETSC_SUCCESS); 5724 } 5725 5726 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5727 { 5728 PetscSection section; 5729 PetscInt maxHeight; 5730 const char *prefix; 5731 5732 PetscFunctionBegin; 5733 PetscCall(DMClone(dm, cdm)); 5734 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5735 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5736 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5737 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5738 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5739 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5740 PetscCall(DMSetLocalSection(*cdm, section)); 5741 PetscCall(PetscSectionDestroy(§ion)); 5742 5743 PetscCall(DMSetNumFields(*cdm, 1)); 5744 PetscCall(DMCreateDS(*cdm)); 5745 (*cdm)->cloneOpts = PETSC_TRUE; 5746 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5747 PetscFunctionReturn(PETSC_SUCCESS); 5748 } 5749 5750 PetscErrorCode DMCreateCellCoordinateDM_Plex(DM dm, DM *cdm) 5751 { 5752 DM cgcdm; 5753 PetscSection section; 5754 const char *prefix; 5755 5756 PetscFunctionBegin; 5757 PetscCall(DMGetCoordinateDM(dm, &cgcdm)); 5758 PetscCall(DMClone(cgcdm, cdm)); 5759 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5760 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5761 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cellcdm_")); 5762 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5763 PetscCall(DMSetLocalSection(*cdm, section)); 5764 PetscCall(PetscSectionDestroy(§ion)); 5765 PetscCall(DMSetNumFields(*cdm, 1)); 5766 PetscCall(DMCreateDS(*cdm)); 5767 (*cdm)->cloneOpts = PETSC_TRUE; 5768 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5769 PetscFunctionReturn(PETSC_SUCCESS); 5770 } 5771 5772 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5773 { 5774 Vec coordsLocal, cellCoordsLocal; 5775 DM coordsDM, cellCoordsDM; 5776 5777 PetscFunctionBegin; 5778 *field = NULL; 5779 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5780 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5781 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5782 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5783 if (coordsLocal && coordsDM) { 5784 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5785 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5786 } 5787 PetscFunctionReturn(PETSC_SUCCESS); 5788 } 5789 5790 /*@ 5791 DMPlexGetConeSection - Return a section which describes the layout of cone data 5792 5793 Not Collective 5794 5795 Input Parameter: 5796 . dm - The `DMPLEX` object 5797 5798 Output Parameter: 5799 . section - The `PetscSection` object 5800 5801 Level: developer 5802 5803 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5804 @*/ 5805 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5806 { 5807 DM_Plex *mesh = (DM_Plex *)dm->data; 5808 5809 PetscFunctionBegin; 5810 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5811 if (section) *section = mesh->coneSection; 5812 PetscFunctionReturn(PETSC_SUCCESS); 5813 } 5814 5815 /*@ 5816 DMPlexGetSupportSection - Return a section which describes the layout of support data 5817 5818 Not Collective 5819 5820 Input Parameter: 5821 . dm - The `DMPLEX` object 5822 5823 Output Parameter: 5824 . section - The `PetscSection` object 5825 5826 Level: developer 5827 5828 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5829 @*/ 5830 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5831 { 5832 DM_Plex *mesh = (DM_Plex *)dm->data; 5833 5834 PetscFunctionBegin; 5835 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5836 if (section) *section = mesh->supportSection; 5837 PetscFunctionReturn(PETSC_SUCCESS); 5838 } 5839 5840 /*@C 5841 DMPlexGetCones - Return cone data 5842 5843 Not Collective 5844 5845 Input Parameter: 5846 . dm - The `DMPLEX` object 5847 5848 Output Parameter: 5849 . cones - The cone for each point 5850 5851 Level: developer 5852 5853 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5854 @*/ 5855 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5856 { 5857 DM_Plex *mesh = (DM_Plex *)dm->data; 5858 5859 PetscFunctionBegin; 5860 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5861 if (cones) *cones = mesh->cones; 5862 PetscFunctionReturn(PETSC_SUCCESS); 5863 } 5864 5865 /*@C 5866 DMPlexGetConeOrientations - Return cone orientation data 5867 5868 Not Collective 5869 5870 Input Parameter: 5871 . dm - The `DMPLEX` object 5872 5873 Output Parameter: 5874 . coneOrientations - The array of cone orientations for all points 5875 5876 Level: developer 5877 5878 Notes: 5879 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5880 as returned by `DMPlexGetConeOrientation()`. 5881 5882 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5883 5884 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5885 @*/ 5886 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5887 { 5888 DM_Plex *mesh = (DM_Plex *)dm->data; 5889 5890 PetscFunctionBegin; 5891 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5892 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5893 PetscFunctionReturn(PETSC_SUCCESS); 5894 } 5895 5896 /* FEM Support */ 5897 5898 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5899 { 5900 PetscInt depth; 5901 5902 PetscFunctionBegin; 5903 PetscCall(DMPlexGetDepth(plex, &depth)); 5904 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5905 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5906 PetscFunctionReturn(PETSC_SUCCESS); 5907 } 5908 5909 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5910 { 5911 PetscInt depth; 5912 5913 PetscFunctionBegin; 5914 PetscCall(DMPlexGetDepth(plex, &depth)); 5915 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5916 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5917 PetscFunctionReturn(PETSC_SUCCESS); 5918 } 5919 5920 /* 5921 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5922 representing a line in the section. 5923 */ 5924 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5925 { 5926 PetscObject obj; 5927 PetscClassId id; 5928 PetscFE fe = NULL; 5929 5930 PetscFunctionBeginHot; 5931 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5932 PetscCall(DMGetField(dm, field, NULL, &obj)); 5933 PetscCall(PetscObjectGetClassId(obj, &id)); 5934 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5935 5936 if (!fe) { 5937 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5938 /* An order k SEM disc has k-1 dofs on an edge */ 5939 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5940 *k = *k / *Nc + 1; 5941 } else { 5942 PetscInt dual_space_size, dim; 5943 PetscDualSpace dsp; 5944 5945 PetscCall(DMGetDimension(dm, &dim)); 5946 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5947 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5948 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5949 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5950 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5951 } 5952 PetscFunctionReturn(PETSC_SUCCESS); 5953 } 5954 5955 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5956 { 5957 PetscFunctionBeginHot; 5958 if (tensor) { 5959 *dof = PetscPowInt(k + 1, dim); 5960 } else { 5961 switch (dim) { 5962 case 1: 5963 *dof = k + 1; 5964 break; 5965 case 2: 5966 *dof = ((k + 1) * (k + 2)) / 2; 5967 break; 5968 case 3: 5969 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5970 break; 5971 default: 5972 *dof = 0; 5973 } 5974 } 5975 PetscFunctionReturn(PETSC_SUCCESS); 5976 } 5977 5978 /*@ 5979 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5980 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5981 section provided (or the section of the `DM`). 5982 5983 Input Parameters: 5984 + dm - The `DM` 5985 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5986 - section - The `PetscSection` to reorder, or `NULL` for the default section 5987 5988 Example: 5989 A typical interpolated single-quad mesh might order points as 5990 .vb 5991 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5992 5993 v4 -- e6 -- v3 5994 | | 5995 e7 c0 e8 5996 | | 5997 v1 -- e5 -- v2 5998 .ve 5999 6000 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 6001 dofs in the order of points, e.g., 6002 .vb 6003 c0 -> [0,1,2,3] 6004 v1 -> [4] 6005 ... 6006 e5 -> [8, 9] 6007 .ve 6008 6009 which corresponds to the dofs 6010 .vb 6011 6 10 11 7 6012 13 2 3 15 6013 12 0 1 14 6014 4 8 9 5 6015 .ve 6016 6017 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 6018 .vb 6019 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 6020 .ve 6021 6022 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 6023 .vb 6024 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 6025 .ve 6026 6027 Level: developer 6028 6029 Notes: 6030 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 6031 degree of the basis. 6032 6033 This is required to run with libCEED. 6034 6035 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 6036 @*/ 6037 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 6038 { 6039 DMLabel label; 6040 PetscInt dim, depth = -1, eStart = -1, Nf; 6041 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 6042 6043 PetscFunctionBegin; 6044 PetscCall(DMGetDimension(dm, &dim)); 6045 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 6046 if (point < 0) { 6047 PetscInt sStart, sEnd; 6048 6049 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6050 point = sEnd - sStart ? sStart : point; 6051 } 6052 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6053 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6054 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6055 if (depth == 1) { 6056 eStart = point; 6057 } else if (depth == dim) { 6058 const PetscInt *cone; 6059 6060 PetscCall(DMPlexGetCone(dm, point, &cone)); 6061 if (dim == 2) eStart = cone[0]; 6062 else if (dim == 3) { 6063 const PetscInt *cone2; 6064 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6065 eStart = cone2[0]; 6066 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 6067 } else PetscCheck(depth < 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 6068 6069 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6070 for (PetscInt d = 1; d <= dim; d++) { 6071 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6072 PetscInt *perm; 6073 6074 for (f = 0; f < Nf; ++f) { 6075 PetscInt dof; 6076 6077 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6078 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6079 if (!continuous && d < dim) continue; 6080 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6081 size += dof * Nc; 6082 } 6083 PetscCall(PetscMalloc1(size, &perm)); 6084 for (f = 0; f < Nf; ++f) { 6085 switch (d) { 6086 case 1: 6087 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6088 if (!continuous && d < dim) continue; 6089 /* 6090 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6091 We want [ vtx0; edge of length k-1; vtx1 ] 6092 */ 6093 if (continuous) { 6094 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6095 for (i = 0; i < k - 1; i++) 6096 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6097 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6098 foffset = offset; 6099 } else { 6100 PetscInt dof; 6101 6102 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6103 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6104 foffset = offset; 6105 } 6106 break; 6107 case 2: 6108 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6109 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6110 if (!continuous && d < dim) continue; 6111 /* The SEM order is 6112 6113 v_lb, {e_b}, v_rb, 6114 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6115 v_lt, reverse {e_t}, v_rt 6116 */ 6117 if (continuous) { 6118 const PetscInt of = 0; 6119 const PetscInt oeb = of + PetscSqr(k - 1); 6120 const PetscInt oer = oeb + (k - 1); 6121 const PetscInt oet = oer + (k - 1); 6122 const PetscInt oel = oet + (k - 1); 6123 const PetscInt ovlb = oel + (k - 1); 6124 const PetscInt ovrb = ovlb + 1; 6125 const PetscInt ovrt = ovrb + 1; 6126 const PetscInt ovlt = ovrt + 1; 6127 PetscInt o; 6128 6129 /* bottom */ 6130 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6131 for (o = oeb; o < oer; ++o) 6132 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6133 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6134 /* middle */ 6135 for (i = 0; i < k - 1; ++i) { 6136 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6137 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6138 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6139 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6140 } 6141 /* top */ 6142 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6143 for (o = oel - 1; o >= oet; --o) 6144 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6145 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6146 foffset = offset; 6147 } else { 6148 PetscInt dof; 6149 6150 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6151 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6152 foffset = offset; 6153 } 6154 break; 6155 case 3: 6156 /* The original hex closure is 6157 6158 {c, 6159 f_b, f_t, f_f, f_b, f_r, f_l, 6160 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6161 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6162 */ 6163 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6164 if (!continuous && d < dim) continue; 6165 /* The SEM order is 6166 Bottom Slice 6167 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6168 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6169 v_blb, {e_bb}, v_brb, 6170 6171 Middle Slice (j) 6172 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6173 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6174 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6175 6176 Top Slice 6177 v_tlf, {e_tf}, v_trf, 6178 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6179 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6180 */ 6181 if (continuous) { 6182 const PetscInt oc = 0; 6183 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6184 const PetscInt oft = ofb + PetscSqr(k - 1); 6185 const PetscInt off = oft + PetscSqr(k - 1); 6186 const PetscInt ofk = off + PetscSqr(k - 1); 6187 const PetscInt ofr = ofk + PetscSqr(k - 1); 6188 const PetscInt ofl = ofr + PetscSqr(k - 1); 6189 const PetscInt oebl = ofl + PetscSqr(k - 1); 6190 const PetscInt oebb = oebl + (k - 1); 6191 const PetscInt oebr = oebb + (k - 1); 6192 const PetscInt oebf = oebr + (k - 1); 6193 const PetscInt oetf = oebf + (k - 1); 6194 const PetscInt oetr = oetf + (k - 1); 6195 const PetscInt oetb = oetr + (k - 1); 6196 const PetscInt oetl = oetb + (k - 1); 6197 const PetscInt oerf = oetl + (k - 1); 6198 const PetscInt oelf = oerf + (k - 1); 6199 const PetscInt oelb = oelf + (k - 1); 6200 const PetscInt oerb = oelb + (k - 1); 6201 const PetscInt ovblf = oerb + (k - 1); 6202 const PetscInt ovblb = ovblf + 1; 6203 const PetscInt ovbrb = ovblb + 1; 6204 const PetscInt ovbrf = ovbrb + 1; 6205 const PetscInt ovtlf = ovbrf + 1; 6206 const PetscInt ovtrf = ovtlf + 1; 6207 const PetscInt ovtrb = ovtrf + 1; 6208 const PetscInt ovtlb = ovtrb + 1; 6209 PetscInt o, n; 6210 6211 /* Bottom Slice */ 6212 /* bottom */ 6213 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6214 for (o = oetf - 1; o >= oebf; --o) 6215 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6216 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6217 /* middle */ 6218 for (i = 0; i < k - 1; ++i) { 6219 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6220 for (n = 0; n < k - 1; ++n) { 6221 o = ofb + n * (k - 1) + i; 6222 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6223 } 6224 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6225 } 6226 /* top */ 6227 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6228 for (o = oebb; o < oebr; ++o) 6229 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6230 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6231 6232 /* Middle Slice */ 6233 for (j = 0; j < k - 1; ++j) { 6234 /* bottom */ 6235 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6236 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6237 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6238 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6239 /* middle */ 6240 for (i = 0; i < k - 1; ++i) { 6241 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6242 for (n = 0; n < k - 1; ++n) 6243 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6244 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6245 } 6246 /* top */ 6247 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6248 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6249 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6250 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6251 } 6252 6253 /* Top Slice */ 6254 /* bottom */ 6255 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6256 for (o = oetf; o < oetr; ++o) 6257 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6258 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6259 /* middle */ 6260 for (i = 0; i < k - 1; ++i) { 6261 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6262 for (n = 0; n < k - 1; ++n) 6263 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6264 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6265 } 6266 /* top */ 6267 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6268 for (o = oetl - 1; o >= oetb; --o) 6269 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6270 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6271 6272 foffset = offset; 6273 } else { 6274 PetscInt dof; 6275 6276 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6277 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6278 foffset = offset; 6279 } 6280 break; 6281 default: 6282 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6283 } 6284 } 6285 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6286 /* Check permutation */ 6287 { 6288 PetscInt *check; 6289 6290 PetscCall(PetscMalloc1(size, &check)); 6291 for (i = 0; i < size; ++i) { 6292 check[i] = -1; 6293 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6294 } 6295 for (i = 0; i < size; ++i) check[perm[i]] = i; 6296 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6297 PetscCall(PetscFree(check)); 6298 } 6299 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6300 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6301 PetscInt *loc_perm; 6302 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6303 for (PetscInt i = 0; i < size; i++) { 6304 loc_perm[i] = perm[i]; 6305 loc_perm[size + i] = size + perm[i]; 6306 } 6307 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6308 } 6309 } 6310 PetscFunctionReturn(PETSC_SUCCESS); 6311 } 6312 6313 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6314 { 6315 PetscDS prob; 6316 PetscInt depth, Nf, h; 6317 DMLabel label; 6318 6319 PetscFunctionBeginHot; 6320 PetscCall(DMGetDS(dm, &prob)); 6321 Nf = prob->Nf; 6322 label = dm->depthLabel; 6323 *dspace = NULL; 6324 if (field < Nf) { 6325 PetscObject disc = prob->disc[field]; 6326 6327 if (disc->classid == PETSCFE_CLASSID) { 6328 PetscDualSpace dsp; 6329 6330 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6331 PetscCall(DMLabelGetNumValues(label, &depth)); 6332 PetscCall(DMLabelGetValue(label, point, &h)); 6333 h = depth - 1 - h; 6334 if (h) { 6335 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6336 } else { 6337 *dspace = dsp; 6338 } 6339 } 6340 } 6341 PetscFunctionReturn(PETSC_SUCCESS); 6342 } 6343 6344 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6345 { 6346 PetscScalar *array; 6347 const PetscScalar *vArray; 6348 const PetscInt *cone, *coneO; 6349 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6350 6351 PetscFunctionBeginHot; 6352 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6353 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6354 PetscCall(DMPlexGetCone(dm, point, &cone)); 6355 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6356 if (!values || !*values) { 6357 if ((point >= pStart) && (point < pEnd)) { 6358 PetscInt dof; 6359 6360 PetscCall(PetscSectionGetDof(section, point, &dof)); 6361 size += dof; 6362 } 6363 for (p = 0; p < numPoints; ++p) { 6364 const PetscInt cp = cone[p]; 6365 PetscInt dof; 6366 6367 if ((cp < pStart) || (cp >= pEnd)) continue; 6368 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6369 size += dof; 6370 } 6371 if (!values) { 6372 if (csize) *csize = size; 6373 PetscFunctionReturn(PETSC_SUCCESS); 6374 } 6375 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6376 } else { 6377 array = *values; 6378 } 6379 size = 0; 6380 PetscCall(VecGetArrayRead(v, &vArray)); 6381 if ((point >= pStart) && (point < pEnd)) { 6382 PetscInt dof, off, d; 6383 const PetscScalar *varr; 6384 6385 PetscCall(PetscSectionGetDof(section, point, &dof)); 6386 PetscCall(PetscSectionGetOffset(section, point, &off)); 6387 varr = PetscSafePointerPlusOffset(vArray, off); 6388 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6389 size += dof; 6390 } 6391 for (p = 0; p < numPoints; ++p) { 6392 const PetscInt cp = cone[p]; 6393 PetscInt o = coneO[p]; 6394 PetscInt dof, off, d; 6395 const PetscScalar *varr; 6396 6397 if ((cp < pStart) || (cp >= pEnd)) continue; 6398 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6399 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6400 varr = PetscSafePointerPlusOffset(vArray, off); 6401 if (o >= 0) { 6402 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6403 } else { 6404 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6405 } 6406 size += dof; 6407 } 6408 PetscCall(VecRestoreArrayRead(v, &vArray)); 6409 if (!*values) { 6410 if (csize) *csize = size; 6411 *values = array; 6412 } else { 6413 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6414 *csize = size; 6415 } 6416 PetscFunctionReturn(PETSC_SUCCESS); 6417 } 6418 6419 /* Compress out points not in the section */ 6420 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6421 { 6422 const PetscInt np = *numPoints; 6423 PetscInt pStart, pEnd, p, q; 6424 6425 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6426 for (p = 0, q = 0; p < np; ++p) { 6427 const PetscInt r = points[p * 2]; 6428 if ((r >= pStart) && (r < pEnd)) { 6429 points[q * 2] = r; 6430 points[q * 2 + 1] = points[p * 2 + 1]; 6431 ++q; 6432 } 6433 } 6434 *numPoints = q; 6435 return PETSC_SUCCESS; 6436 } 6437 6438 /* Compressed closure does not apply closure permutation */ 6439 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6440 { 6441 const PetscInt *cla = NULL; 6442 PetscInt np, *pts = NULL; 6443 6444 PetscFunctionBeginHot; 6445 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6446 if (!ornt && *clPoints) { 6447 PetscInt dof, off; 6448 6449 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6450 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6451 PetscCall(ISGetIndices(*clPoints, &cla)); 6452 np = dof / 2; 6453 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6454 } else { 6455 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6456 PetscCall(CompressPoints_Private(section, &np, pts)); 6457 } 6458 *numPoints = np; 6459 *points = pts; 6460 *clp = cla; 6461 PetscFunctionReturn(PETSC_SUCCESS); 6462 } 6463 6464 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6465 { 6466 PetscFunctionBeginHot; 6467 if (!*clPoints) { 6468 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6469 } else { 6470 PetscCall(ISRestoreIndices(*clPoints, clp)); 6471 } 6472 *numPoints = 0; 6473 *points = NULL; 6474 *clSec = NULL; 6475 *clPoints = NULL; 6476 *clp = NULL; 6477 PetscFunctionReturn(PETSC_SUCCESS); 6478 } 6479 6480 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6481 { 6482 PetscInt offset = 0, p; 6483 const PetscInt **perms = NULL; 6484 const PetscScalar **flips = NULL; 6485 6486 PetscFunctionBeginHot; 6487 *size = 0; 6488 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6489 for (p = 0; p < numPoints; p++) { 6490 const PetscInt point = points[2 * p]; 6491 const PetscInt *perm = perms ? perms[p] : NULL; 6492 const PetscScalar *flip = flips ? flips[p] : NULL; 6493 PetscInt dof, off, d; 6494 const PetscScalar *varr; 6495 6496 PetscCall(PetscSectionGetDof(section, point, &dof)); 6497 PetscCall(PetscSectionGetOffset(section, point, &off)); 6498 varr = PetscSafePointerPlusOffset(vArray, off); 6499 if (clperm) { 6500 if (perm) { 6501 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6502 } else { 6503 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6504 } 6505 if (flip) { 6506 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6507 } 6508 } else { 6509 if (perm) { 6510 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6511 } else { 6512 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6513 } 6514 if (flip) { 6515 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6516 } 6517 } 6518 offset += dof; 6519 } 6520 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6521 *size = offset; 6522 PetscFunctionReturn(PETSC_SUCCESS); 6523 } 6524 6525 static inline PetscErrorCode DMPlexVecGetClosure_Fields_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6526 { 6527 PetscInt offset = 0, f; 6528 6529 PetscFunctionBeginHot; 6530 *size = 0; 6531 for (f = 0; f < numFields; ++f) { 6532 PetscInt p; 6533 const PetscInt **perms = NULL; 6534 const PetscScalar **flips = NULL; 6535 6536 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6537 for (p = 0; p < numPoints; p++) { 6538 const PetscInt point = points[2 * p]; 6539 PetscInt fdof, foff, b; 6540 const PetscScalar *varr; 6541 const PetscInt *perm = perms ? perms[p] : NULL; 6542 const PetscScalar *flip = flips ? flips[p] : NULL; 6543 6544 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6545 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6546 varr = &vArray[foff]; 6547 if (clperm) { 6548 if (perm) { 6549 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6550 } else { 6551 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6552 } 6553 if (flip) { 6554 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6555 } 6556 } else { 6557 if (perm) { 6558 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6559 } else { 6560 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6561 } 6562 if (flip) { 6563 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6564 } 6565 } 6566 offset += fdof; 6567 } 6568 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6569 } 6570 *size = offset; 6571 PetscFunctionReturn(PETSC_SUCCESS); 6572 } 6573 6574 /*@C 6575 DMPlexVecGetOrientedClosure - Get an array of the values on the closure of 'point' with a given orientation, optionally applying the closure permutation. 6576 6577 Not collective 6578 6579 Input Parameters: 6580 + dm - The `DM` 6581 . section - The section describing the layout in `v`, or `NULL` to use the default section 6582 . useClPerm - Flag for whether the provided closure permutation should be applied to the values 6583 . v - The local vector 6584 . point - The point in the `DM` 6585 - ornt - The orientation of the cell, an integer giving the prescription for cone traversal. Typically, this will be 0. 6586 6587 Input/Output Parameters: 6588 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6589 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6590 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6591 6592 Level: advanced 6593 6594 Notes: 6595 `DMPlexVecGetOrientedClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6596 calling function. This is because `DMPlexVecGetOrientedClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6597 assembly function, and a user may already have allocated storage for this operation. 6598 6599 Fortran Notes: 6600 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6601 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6602 6603 `values` must be declared with 6604 .vb 6605 PetscScalar,dimension(:),pointer :: values 6606 .ve 6607 and it will be allocated internally by PETSc to hold the values returned 6608 6609 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexGetCellCoordinates()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()` 6610 @*/ 6611 PetscErrorCode DMPlexVecGetOrientedClosure(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6612 { 6613 PetscSection clSection; 6614 IS clPoints; 6615 PetscInt *points = NULL; 6616 const PetscInt *clp, *perm = NULL; 6617 PetscInt depth, numFields, numPoints, asize; 6618 6619 PetscFunctionBeginHot; 6620 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6621 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6622 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6623 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6624 PetscCall(DMPlexGetDepth(dm, &depth)); 6625 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6626 if (depth == 1 && numFields < 2) { 6627 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6628 PetscFunctionReturn(PETSC_SUCCESS); 6629 } 6630 /* Get points */ 6631 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6632 /* Get sizes */ 6633 asize = 0; 6634 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6635 PetscInt dof; 6636 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6637 asize += dof; 6638 } 6639 if (values) { 6640 const PetscScalar *vArray; 6641 PetscInt size; 6642 6643 if (*values) { 6644 PetscCheck(*csize >= asize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %" PetscInt_FMT " not sufficient to hold closure size %" PetscInt_FMT, *csize, asize); 6645 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6646 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6647 PetscCall(VecGetArrayRead(v, &vArray)); 6648 /* Get values */ 6649 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6650 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6651 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6652 /* Cleanup array */ 6653 PetscCall(VecRestoreArrayRead(v, &vArray)); 6654 } 6655 if (csize) *csize = asize; 6656 /* Cleanup points */ 6657 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6658 PetscFunctionReturn(PETSC_SUCCESS); 6659 } 6660 6661 /*@C 6662 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6663 6664 Not collective 6665 6666 Input Parameters: 6667 + dm - The `DM` 6668 . section - The section describing the layout in `v`, or `NULL` to use the default section 6669 . v - The local vector 6670 - point - The point in the `DM` 6671 6672 Input/Output Parameters: 6673 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6674 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6675 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6676 6677 Level: intermediate 6678 6679 Notes: 6680 This is used for getting the all values in a `Vec` in the closure of a mesh point. 6681 To get only the values in the closure of a mesh point at a specific depth (for example, at mesh vertices), use `DMPlexVecGetClosureAtDepth()`. 6682 6683 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6684 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6685 assembly function, and a user may already have allocated storage for this operation. 6686 6687 A typical use could be 6688 .vb 6689 values = NULL; 6690 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6691 for (cl = 0; cl < clSize; ++cl) { 6692 <Compute on closure> 6693 } 6694 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6695 .ve 6696 or 6697 .vb 6698 PetscMalloc1(clMaxSize, &values); 6699 for (p = pStart; p < pEnd; ++p) { 6700 clSize = clMaxSize; 6701 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6702 for (cl = 0; cl < clSize; ++cl) { 6703 <Compute on closure> 6704 } 6705 } 6706 PetscFree(values); 6707 .ve 6708 6709 Fortran Notes: 6710 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6711 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6712 6713 `values` must be declared with 6714 .vb 6715 PetscScalar,dimension(:),pointer :: values 6716 .ve 6717 and it will be allocated internally by PETSc to hold the values returned 6718 6719 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosureAtDepth()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6720 @*/ 6721 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6722 { 6723 PetscFunctionBeginHot; 6724 PetscCall(DMPlexVecGetOrientedClosure(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6725 PetscFunctionReturn(PETSC_SUCCESS); 6726 } 6727 6728 /*@C 6729 DMPlexVecGetClosureAtDepth - Get an array of the values on the closure of 'point' that are at a specific depth 6730 6731 Not collective 6732 6733 Input Parameters: 6734 + dm - The `DM` 6735 . section - The section describing the layout in `v`, or `NULL` to use the default section 6736 . v - The local vector 6737 . depth - The depth of mesh points that should be returned 6738 - point - The point in the `DM` 6739 6740 Input/Output Parameters: 6741 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6742 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6743 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6744 6745 Level: intermediate 6746 6747 Notes: 6748 This is used for getting the values in a `Vec` associated with specific mesh points. 6749 For example, to get only the values at mesh vertices, pass `depth=0`. To get all the values in the closure of a mesh point, use `DMPlexVecGetClosure()`. 6750 6751 `DMPlexVecGetClosureAtDepth()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6752 calling function. This is because `DMPlexVecGetClosureAtDepth()` is typically called in the inner loop of a `Vec` or `Mat` 6753 assembly function, and a user may already have allocated storage for this operation. 6754 6755 A typical use could be 6756 .vb 6757 values = NULL; 6758 PetscCall(DMPlexVecGetClosureAtDepth(dm, NULL, v, p, depth, &clSize, &values)); 6759 for (cl = 0; cl < clSize; ++cl) { 6760 <Compute on closure> 6761 } 6762 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6763 .ve 6764 or 6765 .vb 6766 PetscMalloc1(clMaxSize, &values); 6767 for (p = pStart; p < pEnd; ++p) { 6768 clSize = clMaxSize; 6769 PetscCall(DMPlexVecGetClosureAtDepth(dm, NULL, v, p, depth, &clSize, &values)); 6770 for (cl = 0; cl < clSize; ++cl) { 6771 <Compute on closure> 6772 } 6773 } 6774 PetscFree(values); 6775 .ve 6776 6777 Fortran Notes: 6778 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6779 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6780 6781 `values` must be declared with 6782 .vb 6783 PetscScalar,dimension(:),pointer :: values 6784 .ve 6785 and it will be allocated internally by PETSc to hold the values returned 6786 6787 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6788 @*/ 6789 PetscErrorCode DMPlexVecGetClosureAtDepth(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6790 { 6791 DMLabel depthLabel; 6792 PetscSection clSection; 6793 IS clPoints; 6794 PetscScalar *array; 6795 const PetscScalar *vArray; 6796 PetscInt *points = NULL; 6797 const PetscInt *clp, *perm = NULL; 6798 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6799 6800 PetscFunctionBeginHot; 6801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6802 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6803 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6804 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6805 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6806 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6807 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6808 if (mdepth == 1 && numFields < 2) { 6809 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6810 PetscFunctionReturn(PETSC_SUCCESS); 6811 } 6812 /* Get points */ 6813 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6814 for (clsize = 0, p = 0; p < Np; p++) { 6815 PetscInt dof; 6816 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6817 clsize += dof; 6818 } 6819 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6820 /* Filter points */ 6821 for (p = 0; p < numPoints * 2; p += 2) { 6822 PetscInt dep; 6823 6824 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6825 if (dep != depth) continue; 6826 points[Np * 2 + 0] = points[p]; 6827 points[Np * 2 + 1] = points[p + 1]; 6828 ++Np; 6829 } 6830 /* Get array */ 6831 if (!values || !*values) { 6832 PetscInt asize = 0, dof; 6833 6834 for (p = 0; p < Np * 2; p += 2) { 6835 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6836 asize += dof; 6837 } 6838 if (!values) { 6839 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6840 if (csize) *csize = asize; 6841 PetscFunctionReturn(PETSC_SUCCESS); 6842 } 6843 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6844 } else { 6845 array = *values; 6846 } 6847 PetscCall(VecGetArrayRead(v, &vArray)); 6848 /* Get values */ 6849 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6850 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6851 /* Cleanup points */ 6852 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6853 /* Cleanup array */ 6854 PetscCall(VecRestoreArrayRead(v, &vArray)); 6855 if (!*values) { 6856 if (csize) *csize = size; 6857 *values = array; 6858 } else { 6859 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6860 *csize = size; 6861 } 6862 PetscFunctionReturn(PETSC_SUCCESS); 6863 } 6864 6865 /*@C 6866 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6867 6868 Not collective 6869 6870 Input Parameters: 6871 + dm - The `DM` 6872 . section - The section describing the layout in `v`, or `NULL` to use the default section 6873 . v - The local vector 6874 . point - The point in the `DM` 6875 . csize - The number of values in the closure, or `NULL` 6876 - values - The array of values 6877 6878 Level: intermediate 6879 6880 Note: 6881 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6882 6883 Fortran Note: 6884 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6885 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6886 6887 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6888 @*/ 6889 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6890 { 6891 PetscInt size = 0; 6892 6893 PetscFunctionBegin; 6894 /* Should work without recalculating size */ 6895 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6896 *values = NULL; 6897 PetscFunctionReturn(PETSC_SUCCESS); 6898 } 6899 6900 static inline void add(PetscScalar *x, PetscScalar y) 6901 { 6902 *x += y; 6903 } 6904 static inline void insert(PetscScalar *x, PetscScalar y) 6905 { 6906 *x = y; 6907 } 6908 6909 static inline PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[]) 6910 { 6911 PetscInt cdof; /* The number of constraints on this point */ 6912 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6913 PetscScalar *a; 6914 PetscInt off, cind = 0, k; 6915 6916 PetscFunctionBegin; 6917 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6918 PetscCall(PetscSectionGetOffset(section, point, &off)); 6919 a = &array[off]; 6920 if (!cdof || setBC) { 6921 if (clperm) { 6922 if (perm) { 6923 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6924 } else { 6925 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6926 } 6927 } else { 6928 if (perm) { 6929 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6930 } else { 6931 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6932 } 6933 } 6934 } else { 6935 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6936 if (clperm) { 6937 if (perm) { 6938 for (k = 0; k < dof; ++k) { 6939 if ((cind < cdof) && (k == cdofs[cind])) { 6940 ++cind; 6941 continue; 6942 } 6943 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6944 } 6945 } else { 6946 for (k = 0; k < dof; ++k) { 6947 if ((cind < cdof) && (k == cdofs[cind])) { 6948 ++cind; 6949 continue; 6950 } 6951 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6952 } 6953 } 6954 } else { 6955 if (perm) { 6956 for (k = 0; k < dof; ++k) { 6957 if ((cind < cdof) && (k == cdofs[cind])) { 6958 ++cind; 6959 continue; 6960 } 6961 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6962 } 6963 } else { 6964 for (k = 0; k < dof; ++k) { 6965 if ((cind < cdof) && (k == cdofs[cind])) { 6966 ++cind; 6967 continue; 6968 } 6969 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6970 } 6971 } 6972 } 6973 } 6974 PetscFunctionReturn(PETSC_SUCCESS); 6975 } 6976 6977 static inline PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[]) 6978 { 6979 PetscInt cdof; /* The number of constraints on this point */ 6980 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6981 PetscScalar *a; 6982 PetscInt off, cind = 0, k; 6983 6984 PetscFunctionBegin; 6985 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6986 PetscCall(PetscSectionGetOffset(section, point, &off)); 6987 a = &array[off]; 6988 if (cdof) { 6989 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6990 if (clperm) { 6991 if (perm) { 6992 for (k = 0; k < dof; ++k) { 6993 if ((cind < cdof) && (k == cdofs[cind])) { 6994 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6995 cind++; 6996 } 6997 } 6998 } else { 6999 for (k = 0; k < dof; ++k) { 7000 if ((cind < cdof) && (k == cdofs[cind])) { 7001 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 7002 cind++; 7003 } 7004 } 7005 } 7006 } else { 7007 if (perm) { 7008 for (k = 0; k < dof; ++k) { 7009 if ((cind < cdof) && (k == cdofs[cind])) { 7010 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 7011 cind++; 7012 } 7013 } 7014 } else { 7015 for (k = 0; k < dof; ++k) { 7016 if ((cind < cdof) && (k == cdofs[cind])) { 7017 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 7018 cind++; 7019 } 7020 } 7021 } 7022 } 7023 } 7024 PetscFunctionReturn(PETSC_SUCCESS); 7025 } 7026 7027 static inline PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, const PetscInt *perm, const PetscScalar *flip, PetscInt f, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[]) 7028 { 7029 PetscScalar *a; 7030 PetscInt fdof, foff, fcdof, foffset = *offset; 7031 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7032 PetscInt cind = 0, b; 7033 7034 PetscFunctionBegin; 7035 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7036 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 7037 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 7038 a = &array[foff]; 7039 if (!fcdof || setBC) { 7040 if (clperm) { 7041 if (perm) { 7042 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7043 } else { 7044 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7045 } 7046 } else { 7047 if (perm) { 7048 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7049 } else { 7050 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7051 } 7052 } 7053 } else { 7054 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7055 if (clperm) { 7056 if (perm) { 7057 for (b = 0; b < fdof; b++) { 7058 if ((cind < fcdof) && (b == fcdofs[cind])) { 7059 ++cind; 7060 continue; 7061 } 7062 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7063 } 7064 } else { 7065 for (b = 0; b < fdof; b++) { 7066 if ((cind < fcdof) && (b == fcdofs[cind])) { 7067 ++cind; 7068 continue; 7069 } 7070 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7071 } 7072 } 7073 } else { 7074 if (perm) { 7075 for (b = 0; b < fdof; b++) { 7076 if ((cind < fcdof) && (b == fcdofs[cind])) { 7077 ++cind; 7078 continue; 7079 } 7080 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7081 } 7082 } else { 7083 for (b = 0; b < fdof; b++) { 7084 if ((cind < fcdof) && (b == fcdofs[cind])) { 7085 ++cind; 7086 continue; 7087 } 7088 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7089 } 7090 } 7091 } 7092 } 7093 *offset += fdof; 7094 PetscFunctionReturn(PETSC_SUCCESS); 7095 } 7096 7097 static inline PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, PetscInt Ncc, const PetscInt comps[], void (*fuse)(PetscScalar *, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[]) 7098 { 7099 PetscScalar *a; 7100 PetscInt fdof, foff, fcdof, foffset = *offset; 7101 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7102 PetscInt Nc, cind = 0, ncind = 0, b; 7103 PetscBool ncSet, fcSet; 7104 7105 PetscFunctionBegin; 7106 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 7107 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7108 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 7109 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 7110 a = &array[foff]; 7111 if (fcdof) { 7112 /* We just override fcdof and fcdofs with Ncc and comps */ 7113 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7114 if (clperm) { 7115 if (perm) { 7116 if (comps) { 7117 for (b = 0; b < fdof; b++) { 7118 ncSet = fcSet = PETSC_FALSE; 7119 if (b % Nc == comps[ncind]) { 7120 ncind = (ncind + 1) % Ncc; 7121 ncSet = PETSC_TRUE; 7122 } 7123 if ((cind < fcdof) && (b == fcdofs[cind])) { 7124 ++cind; 7125 fcSet = PETSC_TRUE; 7126 } 7127 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7128 } 7129 } else { 7130 for (b = 0; b < fdof; b++) { 7131 if ((cind < fcdof) && (b == fcdofs[cind])) { 7132 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7133 ++cind; 7134 } 7135 } 7136 } 7137 } else { 7138 if (comps) { 7139 for (b = 0; b < fdof; b++) { 7140 ncSet = fcSet = PETSC_FALSE; 7141 if (b % Nc == comps[ncind]) { 7142 ncind = (ncind + 1) % Ncc; 7143 ncSet = PETSC_TRUE; 7144 } 7145 if ((cind < fcdof) && (b == fcdofs[cind])) { 7146 ++cind; 7147 fcSet = PETSC_TRUE; 7148 } 7149 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7150 } 7151 } else { 7152 for (b = 0; b < fdof; b++) { 7153 if ((cind < fcdof) && (b == fcdofs[cind])) { 7154 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7155 ++cind; 7156 } 7157 } 7158 } 7159 } 7160 } else { 7161 if (perm) { 7162 if (comps) { 7163 for (b = 0; b < fdof; b++) { 7164 ncSet = fcSet = PETSC_FALSE; 7165 if (b % Nc == comps[ncind]) { 7166 ncind = (ncind + 1) % Ncc; 7167 ncSet = PETSC_TRUE; 7168 } 7169 if ((cind < fcdof) && (b == fcdofs[cind])) { 7170 ++cind; 7171 fcSet = PETSC_TRUE; 7172 } 7173 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7174 } 7175 } else { 7176 for (b = 0; b < fdof; b++) { 7177 if ((cind < fcdof) && (b == fcdofs[cind])) { 7178 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7179 ++cind; 7180 } 7181 } 7182 } 7183 } else { 7184 if (comps) { 7185 for (b = 0; b < fdof; b++) { 7186 ncSet = fcSet = PETSC_FALSE; 7187 if (b % Nc == comps[ncind]) { 7188 ncind = (ncind + 1) % Ncc; 7189 ncSet = PETSC_TRUE; 7190 } 7191 if ((cind < fcdof) && (b == fcdofs[cind])) { 7192 ++cind; 7193 fcSet = PETSC_TRUE; 7194 } 7195 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7196 } 7197 } else { 7198 for (b = 0; b < fdof; b++) { 7199 if ((cind < fcdof) && (b == fcdofs[cind])) { 7200 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7201 ++cind; 7202 } 7203 } 7204 } 7205 } 7206 } 7207 } 7208 *offset += fdof; 7209 PetscFunctionReturn(PETSC_SUCCESS); 7210 } 7211 7212 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7213 { 7214 PetscScalar *array; 7215 const PetscInt *cone, *coneO; 7216 PetscInt pStart, pEnd, p, numPoints, off, dof; 7217 7218 PetscFunctionBeginHot; 7219 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7220 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7221 PetscCall(DMPlexGetCone(dm, point, &cone)); 7222 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7223 PetscCall(VecGetArray(v, &array)); 7224 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7225 const PetscInt cp = !p ? point : cone[p - 1]; 7226 const PetscInt o = !p ? 0 : coneO[p - 1]; 7227 7228 if ((cp < pStart) || (cp >= pEnd)) { 7229 dof = 0; 7230 continue; 7231 } 7232 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7233 /* ADD_VALUES */ 7234 { 7235 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7236 PetscScalar *a; 7237 PetscInt cdof, coff, cind = 0, k; 7238 7239 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7240 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7241 a = &array[coff]; 7242 if (!cdof) { 7243 if (o >= 0) { 7244 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7245 } else { 7246 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7247 } 7248 } else { 7249 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7250 if (o >= 0) { 7251 for (k = 0; k < dof; ++k) { 7252 if ((cind < cdof) && (k == cdofs[cind])) { 7253 ++cind; 7254 continue; 7255 } 7256 a[k] += values[off + k]; 7257 } 7258 } else { 7259 for (k = 0; k < dof; ++k) { 7260 if ((cind < cdof) && (k == cdofs[cind])) { 7261 ++cind; 7262 continue; 7263 } 7264 a[k] += values[off + dof - k - 1]; 7265 } 7266 } 7267 } 7268 } 7269 } 7270 PetscCall(VecRestoreArray(v, &array)); 7271 PetscFunctionReturn(PETSC_SUCCESS); 7272 } 7273 7274 /*@C 7275 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7276 7277 Not collective 7278 7279 Input Parameters: 7280 + dm - The `DM` 7281 . section - The section describing the layout in `v`, or `NULL` to use the default section 7282 . v - The local vector 7283 . point - The point in the `DM` 7284 . values - The array of values 7285 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7286 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7287 7288 Level: intermediate 7289 7290 Note: 7291 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7292 7293 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7294 @*/ 7295 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7296 { 7297 PetscSection clSection; 7298 IS clPoints; 7299 PetscScalar *array; 7300 PetscInt *points = NULL; 7301 const PetscInt *clp, *clperm = NULL; 7302 PetscInt depth, numFields, numPoints, p, clsize; 7303 7304 PetscFunctionBeginHot; 7305 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7306 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7307 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7308 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7309 PetscCall(DMPlexGetDepth(dm, &depth)); 7310 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7311 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7312 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7313 PetscFunctionReturn(PETSC_SUCCESS); 7314 } 7315 /* Get points */ 7316 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7317 for (clsize = 0, p = 0; p < numPoints; p++) { 7318 PetscInt dof; 7319 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7320 clsize += dof; 7321 } 7322 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7323 /* Get array */ 7324 PetscCall(VecGetArray(v, &array)); 7325 /* Get values */ 7326 if (numFields > 0) { 7327 PetscInt offset = 0, f; 7328 for (f = 0; f < numFields; ++f) { 7329 const PetscInt **perms = NULL; 7330 const PetscScalar **flips = NULL; 7331 7332 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7333 switch (mode) { 7334 case INSERT_VALUES: 7335 for (p = 0; p < numPoints; p++) { 7336 const PetscInt point = points[2 * p]; 7337 const PetscInt *perm = perms ? perms[p] : NULL; 7338 const PetscScalar *flip = flips ? flips[p] : NULL; 7339 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7340 } 7341 break; 7342 case INSERT_ALL_VALUES: 7343 for (p = 0; p < numPoints; p++) { 7344 const PetscInt point = points[2 * p]; 7345 const PetscInt *perm = perms ? perms[p] : NULL; 7346 const PetscScalar *flip = flips ? flips[p] : NULL; 7347 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7348 } 7349 break; 7350 case INSERT_BC_VALUES: 7351 for (p = 0; p < numPoints; p++) { 7352 const PetscInt point = points[2 * p]; 7353 const PetscInt *perm = perms ? perms[p] : NULL; 7354 const PetscScalar *flip = flips ? flips[p] : NULL; 7355 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7356 } 7357 break; 7358 case ADD_VALUES: 7359 for (p = 0; p < numPoints; p++) { 7360 const PetscInt point = points[2 * p]; 7361 const PetscInt *perm = perms ? perms[p] : NULL; 7362 const PetscScalar *flip = flips ? flips[p] : NULL; 7363 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7364 } 7365 break; 7366 case ADD_ALL_VALUES: 7367 for (p = 0; p < numPoints; p++) { 7368 const PetscInt point = points[2 * p]; 7369 const PetscInt *perm = perms ? perms[p] : NULL; 7370 const PetscScalar *flip = flips ? flips[p] : NULL; 7371 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7372 } 7373 break; 7374 case ADD_BC_VALUES: 7375 for (p = 0; p < numPoints; p++) { 7376 const PetscInt point = points[2 * p]; 7377 const PetscInt *perm = perms ? perms[p] : NULL; 7378 const PetscScalar *flip = flips ? flips[p] : NULL; 7379 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7380 } 7381 break; 7382 default: 7383 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7384 } 7385 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7386 } 7387 } else { 7388 PetscInt dof, off; 7389 const PetscInt **perms = NULL; 7390 const PetscScalar **flips = NULL; 7391 7392 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7393 switch (mode) { 7394 case INSERT_VALUES: 7395 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7396 const PetscInt point = points[2 * p]; 7397 const PetscInt *perm = perms ? perms[p] : NULL; 7398 const PetscScalar *flip = flips ? flips[p] : NULL; 7399 PetscCall(PetscSectionGetDof(section, point, &dof)); 7400 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7401 } 7402 break; 7403 case INSERT_ALL_VALUES: 7404 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7405 const PetscInt point = points[2 * p]; 7406 const PetscInt *perm = perms ? perms[p] : NULL; 7407 const PetscScalar *flip = flips ? flips[p] : NULL; 7408 PetscCall(PetscSectionGetDof(section, point, &dof)); 7409 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7410 } 7411 break; 7412 case INSERT_BC_VALUES: 7413 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7414 const PetscInt point = points[2 * p]; 7415 const PetscInt *perm = perms ? perms[p] : NULL; 7416 const PetscScalar *flip = flips ? flips[p] : NULL; 7417 PetscCall(PetscSectionGetDof(section, point, &dof)); 7418 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7419 } 7420 break; 7421 case ADD_VALUES: 7422 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7423 const PetscInt point = points[2 * p]; 7424 const PetscInt *perm = perms ? perms[p] : NULL; 7425 const PetscScalar *flip = flips ? flips[p] : NULL; 7426 PetscCall(PetscSectionGetDof(section, point, &dof)); 7427 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7428 } 7429 break; 7430 case ADD_ALL_VALUES: 7431 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7432 const PetscInt point = points[2 * p]; 7433 const PetscInt *perm = perms ? perms[p] : NULL; 7434 const PetscScalar *flip = flips ? flips[p] : NULL; 7435 PetscCall(PetscSectionGetDof(section, point, &dof)); 7436 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7437 } 7438 break; 7439 case ADD_BC_VALUES: 7440 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7441 const PetscInt point = points[2 * p]; 7442 const PetscInt *perm = perms ? perms[p] : NULL; 7443 const PetscScalar *flip = flips ? flips[p] : NULL; 7444 PetscCall(PetscSectionGetDof(section, point, &dof)); 7445 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7446 } 7447 break; 7448 default: 7449 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7450 } 7451 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7452 } 7453 /* Cleanup points */ 7454 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7455 /* Cleanup array */ 7456 PetscCall(VecRestoreArray(v, &array)); 7457 PetscFunctionReturn(PETSC_SUCCESS); 7458 } 7459 7460 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7461 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7462 { 7463 PetscFunctionBegin; 7464 *contains = PETSC_TRUE; 7465 if (label) { 7466 PetscInt fdof; 7467 7468 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7469 if (!*contains) { 7470 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7471 *offset += fdof; 7472 PetscFunctionReturn(PETSC_SUCCESS); 7473 } 7474 } 7475 PetscFunctionReturn(PETSC_SUCCESS); 7476 } 7477 7478 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7479 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], DMLabel label, PetscInt labelId, const PetscScalar values[], InsertMode mode) 7480 { 7481 PetscSection clSection; 7482 IS clPoints; 7483 PetscScalar *array; 7484 PetscInt *points = NULL; 7485 const PetscInt *clp; 7486 PetscInt numFields, numPoints, p; 7487 PetscInt offset = 0, f; 7488 7489 PetscFunctionBeginHot; 7490 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7491 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7492 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7493 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7494 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7495 /* Get points */ 7496 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7497 /* Get array */ 7498 PetscCall(VecGetArray(v, &array)); 7499 /* Get values */ 7500 for (f = 0; f < numFields; ++f) { 7501 const PetscInt **perms = NULL; 7502 const PetscScalar **flips = NULL; 7503 PetscBool contains; 7504 7505 if (!fieldActive[f]) { 7506 for (p = 0; p < numPoints * 2; p += 2) { 7507 PetscInt fdof; 7508 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7509 offset += fdof; 7510 } 7511 continue; 7512 } 7513 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7514 switch (mode) { 7515 case INSERT_VALUES: 7516 for (p = 0; p < numPoints; p++) { 7517 const PetscInt point = points[2 * p]; 7518 const PetscInt *perm = perms ? perms[p] : NULL; 7519 const PetscScalar *flip = flips ? flips[p] : NULL; 7520 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7521 if (!contains) continue; 7522 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7523 } 7524 break; 7525 case INSERT_ALL_VALUES: 7526 for (p = 0; p < numPoints; p++) { 7527 const PetscInt point = points[2 * p]; 7528 const PetscInt *perm = perms ? perms[p] : NULL; 7529 const PetscScalar *flip = flips ? flips[p] : NULL; 7530 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7531 if (!contains) continue; 7532 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7533 } 7534 break; 7535 case INSERT_BC_VALUES: 7536 for (p = 0; p < numPoints; p++) { 7537 const PetscInt point = points[2 * p]; 7538 const PetscInt *perm = perms ? perms[p] : NULL; 7539 const PetscScalar *flip = flips ? flips[p] : NULL; 7540 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7541 if (!contains) continue; 7542 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7543 } 7544 break; 7545 case ADD_VALUES: 7546 for (p = 0; p < numPoints; p++) { 7547 const PetscInt point = points[2 * p]; 7548 const PetscInt *perm = perms ? perms[p] : NULL; 7549 const PetscScalar *flip = flips ? flips[p] : NULL; 7550 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7551 if (!contains) continue; 7552 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7553 } 7554 break; 7555 case ADD_ALL_VALUES: 7556 for (p = 0; p < numPoints; p++) { 7557 const PetscInt point = points[2 * p]; 7558 const PetscInt *perm = perms ? perms[p] : NULL; 7559 const PetscScalar *flip = flips ? flips[p] : NULL; 7560 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7561 if (!contains) continue; 7562 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7563 } 7564 break; 7565 default: 7566 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7567 } 7568 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7569 } 7570 /* Cleanup points */ 7571 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7572 /* Cleanup array */ 7573 PetscCall(VecRestoreArray(v, &array)); 7574 PetscFunctionReturn(PETSC_SUCCESS); 7575 } 7576 7577 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7578 { 7579 PetscMPIInt rank; 7580 PetscInt i, j; 7581 7582 PetscFunctionBegin; 7583 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7584 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7585 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7586 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7587 numCIndices = numCIndices ? numCIndices : numRIndices; 7588 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7589 for (i = 0; i < numRIndices; i++) { 7590 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7591 for (j = 0; j < numCIndices; j++) { 7592 #if defined(PETSC_USE_COMPLEX) 7593 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7594 #else 7595 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7596 #endif 7597 } 7598 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7599 } 7600 PetscFunctionReturn(PETSC_SUCCESS); 7601 } 7602 7603 /* 7604 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7605 7606 Input Parameters: 7607 + section - The section for this data layout 7608 . islocal - Is the section (and thus indices being requested) local or global? 7609 . point - The point contributing dofs with these indices 7610 . off - The global offset of this point 7611 . loff - The local offset of each field 7612 . setBC - The flag determining whether to include indices of boundary values 7613 . perm - A permutation of the dofs on this point, or NULL 7614 - indperm - A permutation of the entire indices array, or NULL 7615 7616 Output Parameter: 7617 . indices - Indices for dofs on this point 7618 7619 Level: developer 7620 7621 Note: The indices could be local or global, depending on the value of 'off'. 7622 */ 7623 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7624 { 7625 PetscInt dof; /* The number of unknowns on this point */ 7626 PetscInt cdof; /* The number of constraints on this point */ 7627 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7628 PetscInt cind = 0, k; 7629 7630 PetscFunctionBegin; 7631 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7632 PetscCall(PetscSectionGetDof(section, point, &dof)); 7633 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7634 if (!cdof || setBC) { 7635 for (k = 0; k < dof; ++k) { 7636 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7637 const PetscInt ind = indperm ? indperm[preind] : preind; 7638 7639 indices[ind] = off + k; 7640 } 7641 } else { 7642 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7643 for (k = 0; k < dof; ++k) { 7644 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7645 const PetscInt ind = indperm ? indperm[preind] : preind; 7646 7647 if ((cind < cdof) && (k == cdofs[cind])) { 7648 /* Insert check for returning constrained indices */ 7649 indices[ind] = -(off + k + 1); 7650 ++cind; 7651 } else { 7652 indices[ind] = off + k - (islocal ? 0 : cind); 7653 } 7654 } 7655 } 7656 *loff += dof; 7657 PetscFunctionReturn(PETSC_SUCCESS); 7658 } 7659 7660 /* 7661 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7662 7663 Input Parameters: 7664 + section - a section (global or local) 7665 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7666 . point - point within section 7667 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7668 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7669 . setBC - identify constrained (boundary condition) points via involution. 7670 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7671 . permsoff - offset 7672 - indperm - index permutation 7673 7674 Output Parameter: 7675 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7676 . indices - array to hold indices (as defined by section) of each dof associated with point 7677 7678 Notes: 7679 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7680 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7681 in the local vector. 7682 7683 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7684 significant). It is invalid to call with a global section and setBC=true. 7685 7686 Developer Note: 7687 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7688 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7689 offset could be obtained from the section instead of passing it explicitly as we do now. 7690 7691 Example: 7692 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7693 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7694 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7695 The global vector does not store constrained dofs, so when this function returns global indices, say {110, -112, 111}, the value of -112 is an arbitrary flag that should not be interpreted beyond its sign. 7696 7697 Level: developer 7698 */ 7699 PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7700 { 7701 PetscInt numFields, foff, f; 7702 7703 PetscFunctionBegin; 7704 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7705 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7706 for (f = 0, foff = 0; f < numFields; ++f) { 7707 PetscInt fdof, cfdof; 7708 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7709 PetscInt cind = 0, b; 7710 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7711 7712 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7713 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7714 if (!cfdof || setBC) { 7715 for (b = 0; b < fdof; ++b) { 7716 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7717 const PetscInt ind = indperm ? indperm[preind] : preind; 7718 7719 indices[ind] = off + foff + b; 7720 } 7721 } else { 7722 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7723 for (b = 0; b < fdof; ++b) { 7724 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7725 const PetscInt ind = indperm ? indperm[preind] : preind; 7726 7727 if ((cind < cfdof) && (b == fcdofs[cind])) { 7728 indices[ind] = -(off + foff + b + 1); 7729 ++cind; 7730 } else { 7731 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7732 } 7733 } 7734 } 7735 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7736 foffs[f] += fdof; 7737 } 7738 PetscFunctionReturn(PETSC_SUCCESS); 7739 } 7740 7741 /* 7742 This version believes the globalSection offsets for each field, rather than just the point offset 7743 7744 . foffs - The offset into 'indices' for each field, since it is segregated by field 7745 7746 Notes: 7747 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7748 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7749 */ 7750 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7751 { 7752 PetscInt numFields, foff, f; 7753 7754 PetscFunctionBegin; 7755 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7756 for (f = 0; f < numFields; ++f) { 7757 PetscInt fdof, cfdof; 7758 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7759 PetscInt cind = 0, b; 7760 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7761 7762 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7763 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7764 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7765 if (!cfdof) { 7766 for (b = 0; b < fdof; ++b) { 7767 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7768 const PetscInt ind = indperm ? indperm[preind] : preind; 7769 7770 indices[ind] = foff + b; 7771 } 7772 } else { 7773 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7774 for (b = 0; b < fdof; ++b) { 7775 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7776 const PetscInt ind = indperm ? indperm[preind] : preind; 7777 7778 if ((cind < cfdof) && (b == fcdofs[cind])) { 7779 indices[ind] = -(foff + b + 1); 7780 ++cind; 7781 } else { 7782 indices[ind] = foff + b - cind; 7783 } 7784 } 7785 } 7786 foffs[f] += fdof; 7787 } 7788 PetscFunctionReturn(PETSC_SUCCESS); 7789 } 7790 7791 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7792 { 7793 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7794 7795 PetscFunctionBegin; 7796 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7797 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7798 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7799 for (PetscInt p = 0; p < nPoints; p++) { 7800 PetscInt b = pnts[2 * p]; 7801 PetscInt bSecDof = 0, bOff; 7802 PetscInt cSecDof = 0; 7803 PetscSection indices_section; 7804 7805 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7806 if (!bSecDof) continue; 7807 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7808 indices_section = cSecDof > 0 ? cSec : section; 7809 if (numFields) { 7810 PetscInt fStart[32], fEnd[32]; 7811 7812 fStart[0] = 0; 7813 fEnd[0] = 0; 7814 for (PetscInt f = 0; f < numFields; f++) { 7815 PetscInt fDof = 0; 7816 7817 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7818 fStart[f + 1] = fStart[f] + fDof; 7819 fEnd[f + 1] = fStart[f + 1]; 7820 } 7821 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7822 // only apply permutations on one side 7823 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7824 for (PetscInt f = 0; f < numFields; f++) { 7825 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7826 } 7827 } else { 7828 PetscInt bEnd = 0; 7829 7830 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7831 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7832 7833 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7834 } 7835 } 7836 PetscFunctionReturn(PETSC_SUCCESS); 7837 } 7838 7839 PETSC_INTERN PetscErrorCode DMPlexAnchorsGetSubMatModification(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscInt offsets[], PetscScalar *outMat[]) 7840 { 7841 Mat cMat; 7842 PetscSection aSec, cSec; 7843 IS aIS; 7844 PetscInt aStart = -1, aEnd = -1; 7845 PetscInt sStart = -1, sEnd = -1; 7846 PetscInt cStart = -1, cEnd = -1; 7847 const PetscInt *anchors; 7848 PetscInt numFields, p; 7849 PetscInt newNumPoints = 0, newNumIndices = 0; 7850 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7851 PetscInt oldOffsets[32]; 7852 PetscInt newOffsets[32]; 7853 PetscInt oldOffsetsCopy[32]; 7854 PetscInt newOffsetsCopy[32]; 7855 PetscScalar *modMat = NULL; 7856 PetscBool anyConstrained = PETSC_FALSE; 7857 7858 PetscFunctionBegin; 7859 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7860 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7861 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7862 7863 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7864 /* if there are point-to-point constraints */ 7865 if (aSec) { 7866 PetscCall(PetscArrayzero(newOffsets, 32)); 7867 PetscCall(PetscArrayzero(oldOffsets, 32)); 7868 PetscCall(ISGetIndices(aIS, &anchors)); 7869 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7870 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7871 /* figure out how many points are going to be in the new element matrix 7872 * (we allow double counting, because it's all just going to be summed 7873 * into the global matrix anyway) */ 7874 for (p = 0; p < 2 * numPoints; p += 2) { 7875 PetscInt b = points[p]; 7876 PetscInt bDof = 0, bSecDof = 0; 7877 7878 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7879 if (!bSecDof) continue; 7880 7881 for (PetscInt f = 0; f < numFields; f++) { 7882 PetscInt fDof = 0; 7883 7884 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7885 oldOffsets[f + 1] += fDof; 7886 } 7887 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7888 if (bDof) { 7889 /* this point is constrained */ 7890 /* it is going to be replaced by its anchors */ 7891 PetscInt bOff, q; 7892 7893 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7894 for (q = 0; q < bDof; q++) { 7895 PetscInt a = anchors[bOff + q]; 7896 PetscInt aDof = 0; 7897 7898 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7899 if (aDof) { 7900 anyConstrained = PETSC_TRUE; 7901 newNumPoints += 1; 7902 } 7903 newNumIndices += aDof; 7904 for (PetscInt f = 0; f < numFields; ++f) { 7905 PetscInt fDof = 0; 7906 7907 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7908 newOffsets[f + 1] += fDof; 7909 } 7910 } 7911 } else { 7912 /* this point is not constrained */ 7913 newNumPoints++; 7914 newNumIndices += bSecDof; 7915 for (PetscInt f = 0; f < numFields; ++f) { 7916 PetscInt fDof; 7917 7918 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7919 newOffsets[f + 1] += fDof; 7920 } 7921 } 7922 } 7923 } 7924 if (!anyConstrained) { 7925 if (outNumPoints) *outNumPoints = 0; 7926 if (outNumIndices) *outNumIndices = 0; 7927 if (outPoints) *outPoints = NULL; 7928 if (outMat) *outMat = NULL; 7929 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7930 PetscFunctionReturn(PETSC_SUCCESS); 7931 } 7932 7933 if (outNumPoints) *outNumPoints = newNumPoints; 7934 if (outNumIndices) *outNumIndices = newNumIndices; 7935 7936 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7937 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7938 7939 if (!outPoints && !outMat) { 7940 if (offsets) { 7941 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7942 } 7943 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7944 PetscFunctionReturn(PETSC_SUCCESS); 7945 } 7946 7947 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7948 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7949 7950 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7951 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7952 7953 /* output arrays */ 7954 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7955 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7956 7957 // get the new Points 7958 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7959 PetscInt b = points[2 * p]; 7960 PetscInt bDof = 0, bSecDof = 0, bOff; 7961 7962 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7963 if (!bSecDof) continue; 7964 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7965 if (bDof) { 7966 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7967 for (PetscInt q = 0; q < bDof; q++) { 7968 PetscInt a = anchors[bOff + q], aDof = 0; 7969 7970 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7971 if (aDof) { 7972 newPoints[2 * newP] = a; 7973 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7974 newP++; 7975 } 7976 } 7977 } else { 7978 newPoints[2 * newP] = b; 7979 newPoints[2 * newP + 1] = points[2 * p + 1]; 7980 newP++; 7981 } 7982 } 7983 7984 if (outMat) { 7985 PetscScalar *tmpMat; 7986 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7987 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7988 7989 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7990 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7991 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7992 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7993 7994 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7995 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7996 7997 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7998 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7999 8000 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 8001 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 8002 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 8003 // for each field, insert the anchor modification into modMat 8004 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 8005 PetscInt fStart = oldOffsets[f]; 8006 PetscInt fNewStart = newOffsets[f]; 8007 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 8008 PetscInt b = points[2 * p]; 8009 PetscInt bDof = 0, bSecDof = 0, bOff; 8010 8011 if (b >= sStart && b < sEnd) { 8012 if (numFields) { 8013 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 8014 } else { 8015 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 8016 } 8017 } 8018 if (!bSecDof) continue; 8019 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 8020 if (bDof) { 8021 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 8022 for (PetscInt q = 0; q < bDof; q++, newP++) { 8023 PetscInt a = anchors[bOff + q], aDof = 0; 8024 8025 if (a >= sStart && a < sEnd) { 8026 if (numFields) { 8027 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 8028 } else { 8029 PetscCall(PetscSectionGetDof(section, a, &aDof)); 8030 } 8031 } 8032 if (aDof) { 8033 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 8034 for (PetscInt d = 0; d < bSecDof; d++) { 8035 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 8036 } 8037 } 8038 oNew += aDof; 8039 } 8040 } else { 8041 // Insert the identity matrix in this block 8042 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 8043 oNew += bSecDof; 8044 newP++; 8045 } 8046 o += bSecDof; 8047 } 8048 } 8049 8050 *outMat = modMat; 8051 8052 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 8053 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 8054 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 8055 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 8056 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 8057 } 8058 PetscCall(ISRestoreIndices(aIS, &anchors)); 8059 8060 /* output */ 8061 if (outPoints) { 8062 *outPoints = newPoints; 8063 } else { 8064 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 8065 } 8066 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 8067 PetscFunctionReturn(PETSC_SUCCESS); 8068 } 8069 8070 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) 8071 { 8072 PetscScalar *modMat = NULL; 8073 PetscInt newNumIndices = -1; 8074 8075 PetscFunctionBegin; 8076 /* 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. 8077 modMat is that matrix C */ 8078 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 8079 if (outNumIndices) *outNumIndices = newNumIndices; 8080 if (modMat) { 8081 const PetscScalar *newValues = values; 8082 8083 if (multiplyRight) { 8084 PetscScalar *newNewValues = NULL; 8085 PetscBLASInt M, N, K; 8086 PetscScalar a = 1.0, b = 0.0; 8087 8088 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); 8089 8090 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 8091 PetscCall(PetscBLASIntCast(numRows, &N)); 8092 PetscCall(PetscBLASIntCast(numIndices, &K)); 8093 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 8094 // row-major to column-major conversion, right multiplication becomes left multiplication 8095 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 8096 numCols = newNumIndices; 8097 newValues = newNewValues; 8098 } 8099 8100 if (multiplyLeft) { 8101 PetscScalar *newNewValues = NULL; 8102 PetscBLASInt M, N, K; 8103 PetscScalar a = 1.0, b = 0.0; 8104 8105 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); 8106 8107 PetscCall(PetscBLASIntCast(numCols, &M)); 8108 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 8109 PetscCall(PetscBLASIntCast(numIndices, &K)); 8110 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 8111 // row-major to column-major conversion, left multiplication becomes right multiplication 8112 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 8113 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 8114 newValues = newNewValues; 8115 } 8116 *outValues = (PetscScalar *)newValues; 8117 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 8118 } 8119 PetscFunctionReturn(PETSC_SUCCESS); 8120 } 8121 8122 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) 8123 { 8124 PetscFunctionBegin; 8125 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 8126 PetscFunctionReturn(PETSC_SUCCESS); 8127 } 8128 8129 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 8130 { 8131 /* Closure ordering */ 8132 PetscSection clSection; 8133 IS clPoints; 8134 const PetscInt *clp; 8135 PetscInt *points; 8136 PetscInt Ncl, Ni = 0; 8137 8138 PetscFunctionBeginHot; 8139 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8140 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 8141 PetscInt dof; 8142 8143 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8144 Ni += dof; 8145 } 8146 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8147 *closureSize = Ni; 8148 PetscFunctionReturn(PETSC_SUCCESS); 8149 } 8150 8151 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) 8152 { 8153 /* Closure ordering */ 8154 PetscSection clSection; 8155 IS clPoints; 8156 const PetscInt *clp; 8157 PetscInt *points; 8158 const PetscInt *clperm = NULL; 8159 /* Dof permutation and sign flips */ 8160 const PetscInt **perms[32] = {NULL}; 8161 const PetscScalar **flips[32] = {NULL}; 8162 PetscScalar *valCopy = NULL; 8163 /* Hanging node constraints */ 8164 PetscInt *pointsC = NULL; 8165 PetscScalar *valuesC = NULL; 8166 PetscInt NclC, NiC; 8167 8168 PetscInt *idx; 8169 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8170 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8171 PetscInt idxStart, idxEnd; 8172 PetscInt nRows, nCols; 8173 8174 PetscFunctionBeginHot; 8175 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8176 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8177 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8178 PetscAssertPointer(numRows, 6); 8179 PetscAssertPointer(numCols, 7); 8180 if (indices) PetscAssertPointer(indices, 8); 8181 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8182 if (values) PetscAssertPointer(values, 10); 8183 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8184 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8185 PetscCall(PetscArrayzero(offsets, 32)); 8186 /* 1) Get points in closure */ 8187 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8188 if (useClPerm) { 8189 PetscInt depth, clsize; 8190 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8191 for (clsize = 0, p = 0; p < Ncl; p++) { 8192 PetscInt dof; 8193 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8194 clsize += dof; 8195 } 8196 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8197 } 8198 /* 2) Get number of indices on these points and field offsets from section */ 8199 for (p = 0; p < Ncl * 2; p += 2) { 8200 PetscInt dof, fdof; 8201 8202 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8203 for (f = 0; f < Nf; ++f) { 8204 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8205 offsets[f + 1] += fdof; 8206 } 8207 Ni += dof; 8208 } 8209 if (*numRows == -1) *numRows = Ni; 8210 if (*numCols == -1) *numCols = Ni; 8211 nRows = *numRows; 8212 nCols = *numCols; 8213 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8214 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8215 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8216 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8217 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8218 for (f = 0; f < PetscMax(1, Nf); ++f) { 8219 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8220 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8221 /* may need to apply sign changes to the element matrix */ 8222 if (values && flips[f]) { 8223 PetscInt foffset = offsets[f]; 8224 8225 for (p = 0; p < Ncl; ++p) { 8226 PetscInt pnt = points[2 * p], fdof; 8227 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8228 8229 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8230 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8231 if (flip) { 8232 PetscInt i, j, k; 8233 8234 if (!valCopy) { 8235 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8236 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8237 *values = valCopy; 8238 } 8239 for (i = 0; i < fdof; ++i) { 8240 PetscScalar fval = flip[i]; 8241 8242 if (multiplyRight) { 8243 for (k = 0; k < nRows; ++k) valCopy[Ni * k + (foffset + i)] *= fval; 8244 } 8245 if (multiplyLeft) { 8246 for (k = 0; k < nCols; ++k) valCopy[nCols * (foffset + i) + k] *= fval; 8247 } 8248 } 8249 } 8250 foffset += fdof; 8251 } 8252 } 8253 } 8254 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8255 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8256 if (NclC) { 8257 if (multiplyRight) *numCols = NiC; 8258 if (multiplyLeft) *numRows = NiC; 8259 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8260 for (f = 0; f < PetscMax(1, Nf); ++f) { 8261 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8262 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8263 } 8264 for (f = 0; f < PetscMax(1, Nf); ++f) { 8265 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8266 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8267 } 8268 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8269 Ncl = NclC; 8270 Ni = NiC; 8271 points = pointsC; 8272 if (values) *values = valuesC; 8273 } 8274 /* 5) Calculate indices */ 8275 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8276 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8277 if (Nf) { 8278 PetscInt idxOff; 8279 PetscBool useFieldOffsets; 8280 8281 if (outOffsets) { 8282 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8283 } 8284 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8285 if (useFieldOffsets) { 8286 for (p = 0; p < Ncl; ++p) { 8287 const PetscInt pnt = points[p * 2]; 8288 8289 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8290 } 8291 } else { 8292 for (p = 0; p < Ncl; ++p) { 8293 const PetscInt pnt = points[p * 2]; 8294 8295 if (pnt < idxStart || pnt >= idxEnd) continue; 8296 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8297 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8298 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8299 * global section. */ 8300 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8301 } 8302 } 8303 } else { 8304 PetscInt off = 0, idxOff; 8305 8306 for (p = 0; p < Ncl; ++p) { 8307 const PetscInt pnt = points[p * 2]; 8308 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8309 8310 if (pnt < idxStart || pnt >= idxEnd) continue; 8311 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8312 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8313 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8314 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8315 } 8316 } 8317 /* 6) Cleanup */ 8318 for (f = 0; f < PetscMax(1, Nf); ++f) { 8319 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8320 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8321 } 8322 if (NclC) { 8323 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8324 } else { 8325 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8326 } 8327 8328 if (indices) *indices = idx; 8329 PetscFunctionReturn(PETSC_SUCCESS); 8330 } 8331 8332 /*@C 8333 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8334 8335 Not collective 8336 8337 Input Parameters: 8338 + dm - The `DM` 8339 . section - The `PetscSection` describing the points (a local section) 8340 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8341 . point - The point defining the closure 8342 - useClPerm - Use the closure point permutation if available 8343 8344 Output Parameters: 8345 + numIndices - The number of dof indices in the closure of point with the input sections 8346 . indices - The dof indices 8347 . outOffsets - Array, of length the number of fields plus 1, to write the field offsets into, or `NULL` 8348 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8349 8350 Level: advanced 8351 8352 Notes: 8353 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8354 8355 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8356 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8357 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8358 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8359 indices (with the above semantics) are implied. 8360 8361 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8362 `PetscSection`, `DMGetGlobalSection()` 8363 @*/ 8364 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8365 { 8366 PetscInt numRows = -1, numCols = -1; 8367 8368 PetscFunctionBeginHot; 8369 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8370 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8371 *numIndices = numRows; 8372 PetscFunctionReturn(PETSC_SUCCESS); 8373 } 8374 8375 /*@C 8376 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8377 8378 Not collective 8379 8380 Input Parameters: 8381 + dm - The `DM` 8382 . section - The `PetscSection` describing the points (a local section) 8383 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8384 . point - The point defining the closure 8385 - useClPerm - Use the closure point permutation if available 8386 8387 Output Parameters: 8388 + numIndices - The number of dof indices in the closure of point with the input sections 8389 . indices - The dof indices 8390 . outOffsets - Array to write the field offsets into, or `NULL` 8391 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8392 8393 Level: advanced 8394 8395 Notes: 8396 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8397 8398 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8399 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8400 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8401 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8402 indices (with the above semantics) are implied. 8403 8404 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8405 @*/ 8406 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8407 { 8408 PetscFunctionBegin; 8409 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8410 PetscAssertPointer(indices, 7); 8411 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8412 PetscFunctionReturn(PETSC_SUCCESS); 8413 } 8414 8415 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8416 { 8417 DM_Plex *mesh = (DM_Plex *)dm->data; 8418 PetscInt *indices; 8419 PetscInt numIndices; 8420 const PetscScalar *valuesOrig = values; 8421 PetscErrorCode ierr; 8422 8423 PetscFunctionBegin; 8424 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8425 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8426 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8427 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8428 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8429 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8430 8431 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8432 8433 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8434 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8435 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8436 if (ierr) { 8437 PetscMPIInt rank; 8438 8439 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8440 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8441 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8442 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8443 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8444 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8445 } 8446 if (mesh->printFEM > 1) { 8447 PetscInt i; 8448 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8449 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8450 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8451 } 8452 8453 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8454 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8455 PetscFunctionReturn(PETSC_SUCCESS); 8456 } 8457 8458 /*@C 8459 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8460 8461 Not collective 8462 8463 Input Parameters: 8464 + dm - The `DM` 8465 . section - The section describing the layout in `v`, or `NULL` to use the default section 8466 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8467 . A - The matrix 8468 . point - The point in the `DM` 8469 . values - The array of values 8470 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8471 8472 Level: intermediate 8473 8474 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8475 @*/ 8476 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8477 { 8478 PetscFunctionBegin; 8479 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8480 PetscFunctionReturn(PETSC_SUCCESS); 8481 } 8482 8483 /*@C 8484 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8485 8486 Not collective 8487 8488 Input Parameters: 8489 + dmRow - The `DM` for the row fields 8490 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8491 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8492 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8493 . dmCol - The `DM` for the column fields 8494 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8495 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8496 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8497 . A - The matrix 8498 . point - The point in the `DM` 8499 . values - The array of values 8500 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8501 8502 Level: intermediate 8503 8504 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8505 @*/ 8506 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) 8507 { 8508 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8509 PetscInt *indicesRow, *indicesCol; 8510 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8511 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8512 8513 PetscErrorCode ierr; 8514 8515 PetscFunctionBegin; 8516 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8517 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8518 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8519 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8520 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8521 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8522 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8523 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8524 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8525 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8526 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8527 8528 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8529 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8530 valuesV1 = valuesV0; 8531 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8532 valuesV2 = valuesV1; 8533 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8534 8535 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8536 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8537 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8538 if (ierr) { 8539 PetscMPIInt rank; 8540 8541 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8542 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8543 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8544 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8545 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8546 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8547 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8548 } 8549 8550 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8551 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8552 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8553 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8554 PetscFunctionReturn(PETSC_SUCCESS); 8555 } 8556 8557 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8558 { 8559 DM_Plex *mesh = (DM_Plex *)dmf->data; 8560 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8561 PetscInt *cpoints = NULL; 8562 PetscInt *findices, *cindices; 8563 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8564 PetscInt foffsets[32], coffsets[32]; 8565 DMPolytopeType ct; 8566 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8567 PetscErrorCode ierr; 8568 8569 PetscFunctionBegin; 8570 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8571 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8572 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8573 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8574 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8575 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8576 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8577 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8578 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8579 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8580 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8581 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8582 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8583 PetscCall(PetscArrayzero(foffsets, 32)); 8584 PetscCall(PetscArrayzero(coffsets, 32)); 8585 /* Column indices */ 8586 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8587 maxFPoints = numCPoints; 8588 /* Compress out points not in the section */ 8589 /* TODO: Squeeze out points with 0 dof as well */ 8590 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8591 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8592 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8593 cpoints[q * 2] = cpoints[p]; 8594 cpoints[q * 2 + 1] = cpoints[p + 1]; 8595 ++q; 8596 } 8597 } 8598 numCPoints = q; 8599 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8600 PetscInt fdof; 8601 8602 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8603 if (!dof) continue; 8604 for (f = 0; f < numFields; ++f) { 8605 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8606 coffsets[f + 1] += fdof; 8607 } 8608 numCIndices += dof; 8609 } 8610 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8611 /* Row indices */ 8612 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8613 { 8614 DMPlexTransform tr; 8615 DMPolytopeType *rct; 8616 PetscInt *rsize, *rcone, *rornt, Nt; 8617 8618 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8619 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8620 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8621 numSubcells = rsize[Nt - 1]; 8622 PetscCall(DMPlexTransformDestroy(&tr)); 8623 } 8624 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8625 for (r = 0, q = 0; r < numSubcells; ++r) { 8626 /* TODO Map from coarse to fine cells */ 8627 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8628 /* Compress out points not in the section */ 8629 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8630 for (p = 0; p < numFPoints * 2; p += 2) { 8631 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8632 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8633 if (!dof) continue; 8634 for (s = 0; s < q; ++s) 8635 if (fpoints[p] == ftotpoints[s * 2]) break; 8636 if (s < q) continue; 8637 ftotpoints[q * 2] = fpoints[p]; 8638 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8639 ++q; 8640 } 8641 } 8642 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8643 } 8644 numFPoints = q; 8645 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8646 PetscInt fdof; 8647 8648 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8649 if (!dof) continue; 8650 for (f = 0; f < numFields; ++f) { 8651 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8652 foffsets[f + 1] += fdof; 8653 } 8654 numFIndices += dof; 8655 } 8656 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8657 8658 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8659 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8660 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8661 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8662 if (numFields) { 8663 const PetscInt **permsF[32] = {NULL}; 8664 const PetscInt **permsC[32] = {NULL}; 8665 8666 for (f = 0; f < numFields; f++) { 8667 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8668 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8669 } 8670 for (p = 0; p < numFPoints; p++) { 8671 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8672 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8673 } 8674 for (p = 0; p < numCPoints; p++) { 8675 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8676 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8677 } 8678 for (f = 0; f < numFields; f++) { 8679 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8680 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8681 } 8682 } else { 8683 const PetscInt **permsF = NULL; 8684 const PetscInt **permsC = NULL; 8685 8686 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8687 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8688 for (p = 0, off = 0; p < numFPoints; p++) { 8689 const PetscInt *perm = permsF ? permsF[p] : NULL; 8690 8691 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8692 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8693 } 8694 for (p = 0, off = 0; p < numCPoints; p++) { 8695 const PetscInt *perm = permsC ? permsC[p] : NULL; 8696 8697 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8698 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8699 } 8700 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8701 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8702 } 8703 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8704 /* TODO: flips */ 8705 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8706 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8707 if (ierr) { 8708 PetscMPIInt rank; 8709 8710 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8711 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8712 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8713 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8714 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8715 } 8716 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8717 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8718 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8719 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8720 PetscFunctionReturn(PETSC_SUCCESS); 8721 } 8722 8723 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8724 { 8725 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8726 PetscInt *cpoints = NULL; 8727 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8728 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8729 DMPolytopeType ct; 8730 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8731 8732 PetscFunctionBegin; 8733 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8734 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8735 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8736 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8737 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8738 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8739 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8740 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8741 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8742 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8743 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8744 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8745 /* Column indices */ 8746 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8747 maxFPoints = numCPoints; 8748 /* Compress out points not in the section */ 8749 /* TODO: Squeeze out points with 0 dof as well */ 8750 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8751 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8752 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8753 cpoints[q * 2] = cpoints[p]; 8754 cpoints[q * 2 + 1] = cpoints[p + 1]; 8755 ++q; 8756 } 8757 } 8758 numCPoints = q; 8759 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8760 PetscInt fdof; 8761 8762 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8763 if (!dof) continue; 8764 for (f = 0; f < numFields; ++f) { 8765 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8766 coffsets[f + 1] += fdof; 8767 } 8768 numCIndices += dof; 8769 } 8770 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8771 /* Row indices */ 8772 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8773 { 8774 DMPlexTransform tr; 8775 DMPolytopeType *rct; 8776 PetscInt *rsize, *rcone, *rornt, Nt; 8777 8778 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8779 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8780 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8781 numSubcells = rsize[Nt - 1]; 8782 PetscCall(DMPlexTransformDestroy(&tr)); 8783 } 8784 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8785 for (r = 0, q = 0; r < numSubcells; ++r) { 8786 /* TODO Map from coarse to fine cells */ 8787 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8788 /* Compress out points not in the section */ 8789 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8790 for (p = 0; p < numFPoints * 2; p += 2) { 8791 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8792 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8793 if (!dof) continue; 8794 for (s = 0; s < q; ++s) 8795 if (fpoints[p] == ftotpoints[s * 2]) break; 8796 if (s < q) continue; 8797 ftotpoints[q * 2] = fpoints[p]; 8798 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8799 ++q; 8800 } 8801 } 8802 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8803 } 8804 numFPoints = q; 8805 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8806 PetscInt fdof; 8807 8808 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8809 if (!dof) continue; 8810 for (f = 0; f < numFields; ++f) { 8811 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8812 foffsets[f + 1] += fdof; 8813 } 8814 numFIndices += dof; 8815 } 8816 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8817 8818 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8819 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8820 if (numFields) { 8821 const PetscInt **permsF[32] = {NULL}; 8822 const PetscInt **permsC[32] = {NULL}; 8823 8824 for (f = 0; f < numFields; f++) { 8825 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8826 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8827 } 8828 for (p = 0; p < numFPoints; p++) { 8829 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8830 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8831 } 8832 for (p = 0; p < numCPoints; p++) { 8833 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8834 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8835 } 8836 for (f = 0; f < numFields; f++) { 8837 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8838 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8839 } 8840 } else { 8841 const PetscInt **permsF = NULL; 8842 const PetscInt **permsC = NULL; 8843 8844 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8845 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8846 for (p = 0, off = 0; p < numFPoints; p++) { 8847 const PetscInt *perm = permsF ? permsF[p] : NULL; 8848 8849 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8850 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8851 } 8852 for (p = 0, off = 0; p < numCPoints; p++) { 8853 const PetscInt *perm = permsC ? permsC[p] : NULL; 8854 8855 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8856 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8857 } 8858 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8859 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8860 } 8861 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8862 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8863 PetscFunctionReturn(PETSC_SUCCESS); 8864 } 8865 8866 /*@ 8867 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8868 8869 Input Parameter: 8870 . dm - The `DMPLEX` object 8871 8872 Output Parameter: 8873 . cellHeight - The height of a cell 8874 8875 Level: developer 8876 8877 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8878 @*/ 8879 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8880 { 8881 DM_Plex *mesh = (DM_Plex *)dm->data; 8882 8883 PetscFunctionBegin; 8884 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8885 PetscAssertPointer(cellHeight, 2); 8886 *cellHeight = mesh->vtkCellHeight; 8887 PetscFunctionReturn(PETSC_SUCCESS); 8888 } 8889 8890 /*@ 8891 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8892 8893 Input Parameters: 8894 + dm - The `DMPLEX` object 8895 - cellHeight - The height of a cell 8896 8897 Level: developer 8898 8899 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8900 @*/ 8901 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8902 { 8903 DM_Plex *mesh = (DM_Plex *)dm->data; 8904 8905 PetscFunctionBegin; 8906 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8907 mesh->vtkCellHeight = cellHeight; 8908 PetscFunctionReturn(PETSC_SUCCESS); 8909 } 8910 8911 /*@ 8912 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8913 8914 Input Parameters: 8915 + dm - The `DMPLEX` object 8916 - ct - The `DMPolytopeType` of the cell 8917 8918 Output Parameters: 8919 + start - The first cell of this type, or `NULL` 8920 - end - The upper bound on this celltype, or `NULL` 8921 8922 Level: advanced 8923 8924 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8925 @*/ 8926 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end) 8927 { 8928 DM_Plex *mesh = (DM_Plex *)dm->data; 8929 DMLabel label; 8930 PetscInt pStart, pEnd; 8931 8932 PetscFunctionBegin; 8933 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8934 if (start) { 8935 PetscAssertPointer(start, 3); 8936 *start = 0; 8937 } 8938 if (end) { 8939 PetscAssertPointer(end, 4); 8940 *end = 0; 8941 } 8942 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8943 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8944 if (mesh->tr) { 8945 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8946 } else { 8947 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8948 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8949 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8950 } 8951 PetscFunctionReturn(PETSC_SUCCESS); 8952 } 8953 8954 /*@ 8955 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8956 8957 Input Parameters: 8958 + dm - The `DMPLEX` object 8959 - depth - The depth for the given point stratum 8960 8961 Output Parameter: 8962 . gsize - The global number of points in the stratum 8963 8964 Level: advanced 8965 8966 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8967 @*/ 8968 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8969 { 8970 PetscSF sf; 8971 const PetscInt *leaves; 8972 PetscInt Nl, loc, start, end, lsize = 0; 8973 8974 PetscFunctionBegin; 8975 PetscCall(DMGetPointSF(dm, &sf)); 8976 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8977 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8978 for (PetscInt p = start; p < end; ++p) { 8979 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8980 if (loc < 0) ++lsize; 8981 } 8982 PetscCallMPI(MPIU_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8983 PetscFunctionReturn(PETSC_SUCCESS); 8984 } 8985 8986 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8987 { 8988 PetscSection section, globalSection; 8989 PetscInt *numbers, p; 8990 8991 PetscFunctionBegin; 8992 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8993 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8994 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8995 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8996 PetscCall(PetscSectionSetUp(section)); 8997 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8998 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8999 for (p = pStart; p < pEnd; ++p) { 9000 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 9001 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 9002 else numbers[p - pStart] += shift; 9003 } 9004 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 9005 if (globalSize) { 9006 PetscLayout layout; 9007 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 9008 PetscCall(PetscLayoutGetSize(layout, globalSize)); 9009 PetscCall(PetscLayoutDestroy(&layout)); 9010 } 9011 PetscCall(PetscSectionDestroy(§ion)); 9012 PetscCall(PetscSectionDestroy(&globalSection)); 9013 PetscFunctionReturn(PETSC_SUCCESS); 9014 } 9015 9016 /*@ 9017 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 9018 9019 Input Parameters: 9020 + dm - The `DMPLEX` object 9021 - includeAll - Whether to include all cells, or just the simplex and box cells 9022 9023 Output Parameter: 9024 . globalCellNumbers - Global cell numbers for all cells on this process 9025 9026 Level: developer 9027 9028 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 9029 @*/ 9030 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 9031 { 9032 PetscInt cellHeight, cStart, cEnd; 9033 9034 PetscFunctionBegin; 9035 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9036 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9037 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 9038 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 9039 PetscFunctionReturn(PETSC_SUCCESS); 9040 } 9041 9042 /*@ 9043 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 9044 9045 Input Parameter: 9046 . dm - The `DMPLEX` object 9047 9048 Output Parameter: 9049 . globalCellNumbers - Global cell numbers for all cells on this process 9050 9051 Level: developer 9052 9053 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 9054 @*/ 9055 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 9056 { 9057 DM_Plex *mesh = (DM_Plex *)dm->data; 9058 9059 PetscFunctionBegin; 9060 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9061 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 9062 *globalCellNumbers = mesh->globalCellNumbers; 9063 PetscFunctionReturn(PETSC_SUCCESS); 9064 } 9065 9066 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 9067 { 9068 PetscInt vStart, vEnd; 9069 9070 PetscFunctionBegin; 9071 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9072 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9073 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 9074 PetscFunctionReturn(PETSC_SUCCESS); 9075 } 9076 9077 /*@ 9078 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 9079 9080 Input Parameter: 9081 . dm - The `DMPLEX` object 9082 9083 Output Parameter: 9084 . globalVertexNumbers - Global vertex numbers for all vertices on this process 9085 9086 Level: developer 9087 9088 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9089 @*/ 9090 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 9091 { 9092 DM_Plex *mesh = (DM_Plex *)dm->data; 9093 9094 PetscFunctionBegin; 9095 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9096 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 9097 *globalVertexNumbers = mesh->globalVertexNumbers; 9098 PetscFunctionReturn(PETSC_SUCCESS); 9099 } 9100 9101 /*@ 9102 DMPlexCreatePointNumbering - Create a global numbering for all points. 9103 9104 Collective 9105 9106 Input Parameter: 9107 . dm - The `DMPLEX` object 9108 9109 Output Parameter: 9110 . globalPointNumbers - Global numbers for all points on this process 9111 9112 Level: developer 9113 9114 Notes: 9115 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 9116 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 9117 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 9118 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 9119 9120 The partitioned mesh is 9121 ``` 9122 (2)--0--(3)--1--(4) (1)--0--(2) 9123 ``` 9124 and its global numbering is 9125 ``` 9126 (3)--0--(4)--1--(5)--2--(6) 9127 ``` 9128 Then the global numbering is provided as 9129 ``` 9130 [0] Number of indices in set 5 9131 [0] 0 0 9132 [0] 1 1 9133 [0] 2 3 9134 [0] 3 4 9135 [0] 4 -6 9136 [1] Number of indices in set 3 9137 [1] 0 2 9138 [1] 1 5 9139 [1] 2 6 9140 ``` 9141 9142 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9143 @*/ 9144 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 9145 { 9146 IS nums[4]; 9147 PetscInt depths[4], gdepths[4], starts[4]; 9148 PetscInt depth, d, shift = 0; 9149 PetscBool empty = PETSC_FALSE; 9150 9151 PetscFunctionBegin; 9152 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9153 PetscCall(DMPlexGetDepth(dm, &depth)); 9154 // For unstratified meshes use dim instead of depth 9155 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9156 // If any stratum is empty, we must mark all empty 9157 for (d = 0; d <= depth; ++d) { 9158 PetscInt end; 9159 9160 depths[d] = depth - d; 9161 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9162 if (!(starts[d] - end)) empty = PETSC_TRUE; 9163 } 9164 if (empty) 9165 for (d = 0; d <= depth; ++d) { 9166 depths[d] = -1; 9167 starts[d] = -1; 9168 } 9169 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9170 PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9171 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]); 9172 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9173 for (d = 0; d <= depth; ++d) { 9174 PetscInt pStart, pEnd, gsize; 9175 9176 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9177 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9178 shift += gsize; 9179 } 9180 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9181 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9182 PetscFunctionReturn(PETSC_SUCCESS); 9183 } 9184 9185 /*@ 9186 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9187 9188 Collective 9189 9190 Input Parameter: 9191 . dm - The `DMPLEX` object 9192 9193 Output Parameter: 9194 . globalEdgeNumbers - Global numbers for all edges on this process 9195 9196 Level: developer 9197 9198 Notes: 9199 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). 9200 9201 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9202 @*/ 9203 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9204 { 9205 PetscSF sf; 9206 PetscInt eStart, eEnd; 9207 9208 PetscFunctionBegin; 9209 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9210 PetscCall(DMGetPointSF(dm, &sf)); 9211 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9212 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9213 PetscFunctionReturn(PETSC_SUCCESS); 9214 } 9215 9216 /*@ 9217 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9218 9219 Input Parameter: 9220 . dm - The `DMPLEX` object 9221 9222 Output Parameter: 9223 . ranks - The rank field 9224 9225 Options Database Key: 9226 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9227 9228 Level: intermediate 9229 9230 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9231 @*/ 9232 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9233 { 9234 DM rdm; 9235 PetscFE fe; 9236 PetscScalar *r; 9237 PetscMPIInt rank; 9238 DMPolytopeType ct; 9239 PetscInt dim, cStart, cEnd, c; 9240 PetscBool simplex; 9241 9242 PetscFunctionBeginUser; 9243 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9244 PetscAssertPointer(ranks, 2); 9245 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9246 PetscCall(DMClone(dm, &rdm)); 9247 PetscCall(DMGetDimension(rdm, &dim)); 9248 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9249 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9250 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9251 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9252 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9253 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9254 PetscCall(PetscFEDestroy(&fe)); 9255 PetscCall(DMCreateDS(rdm)); 9256 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9257 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9258 PetscCall(VecGetArray(*ranks, &r)); 9259 for (c = cStart; c < cEnd; ++c) { 9260 PetscScalar *lr; 9261 9262 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9263 if (lr) *lr = rank; 9264 } 9265 PetscCall(VecRestoreArray(*ranks, &r)); 9266 PetscCall(DMDestroy(&rdm)); 9267 PetscFunctionReturn(PETSC_SUCCESS); 9268 } 9269 9270 /*@ 9271 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9272 9273 Input Parameters: 9274 + dm - The `DMPLEX` 9275 - label - The `DMLabel` 9276 9277 Output Parameter: 9278 . val - The label value field 9279 9280 Options Database Key: 9281 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9282 9283 Level: intermediate 9284 9285 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9286 @*/ 9287 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9288 { 9289 DM rdm, plex; 9290 Vec lval; 9291 PetscSection section; 9292 PetscFE fe; 9293 PetscScalar *v; 9294 PetscInt dim, pStart, pEnd, p, cStart; 9295 DMPolytopeType ct; 9296 char name[PETSC_MAX_PATH_LEN]; 9297 const char *lname, *prefix; 9298 9299 PetscFunctionBeginUser; 9300 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9301 PetscAssertPointer(label, 2); 9302 PetscAssertPointer(val, 3); 9303 PetscCall(DMClone(dm, &rdm)); 9304 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9305 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9306 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9307 PetscCall(DMDestroy(&plex)); 9308 PetscCall(DMGetDimension(rdm, &dim)); 9309 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9310 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9311 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9312 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9313 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9314 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9315 PetscCall(PetscFEDestroy(&fe)); 9316 PetscCall(DMCreateDS(rdm)); 9317 PetscCall(DMCreateGlobalVector(rdm, val)); 9318 PetscCall(DMCreateLocalVector(rdm, &lval)); 9319 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9320 PetscCall(DMGetLocalSection(rdm, §ion)); 9321 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9322 PetscCall(VecGetArray(lval, &v)); 9323 for (p = pStart; p < pEnd; ++p) { 9324 PetscInt cval, dof, off; 9325 9326 PetscCall(PetscSectionGetDof(section, p, &dof)); 9327 if (!dof) continue; 9328 PetscCall(DMLabelGetValue(label, p, &cval)); 9329 PetscCall(PetscSectionGetOffset(section, p, &off)); 9330 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9331 } 9332 PetscCall(VecRestoreArray(lval, &v)); 9333 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9334 PetscCall(VecDestroy(&lval)); 9335 PetscCall(DMDestroy(&rdm)); 9336 PetscFunctionReturn(PETSC_SUCCESS); 9337 } 9338 9339 /*@ 9340 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9341 9342 Input Parameter: 9343 . dm - The `DMPLEX` object 9344 9345 Level: developer 9346 9347 Notes: 9348 This is a useful diagnostic when creating meshes programmatically. 9349 9350 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9351 9352 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9353 @*/ 9354 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9355 { 9356 PetscSection coneSection, supportSection; 9357 const PetscInt *cone, *support; 9358 PetscInt coneSize, c, supportSize, s; 9359 PetscInt pStart, pEnd, p, pp, csize, ssize; 9360 PetscBool storagecheck = PETSC_TRUE; 9361 9362 PetscFunctionBegin; 9363 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9364 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9365 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9366 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9367 /* Check that point p is found in the support of its cone points, and vice versa */ 9368 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9369 for (p = pStart; p < pEnd; ++p) { 9370 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9371 PetscCall(DMPlexGetCone(dm, p, &cone)); 9372 for (c = 0; c < coneSize; ++c) { 9373 PetscBool dup = PETSC_FALSE; 9374 PetscInt d; 9375 for (d = c - 1; d >= 0; --d) { 9376 if (cone[c] == cone[d]) { 9377 dup = PETSC_TRUE; 9378 break; 9379 } 9380 } 9381 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9382 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9383 for (s = 0; s < supportSize; ++s) { 9384 if (support[s] == p) break; 9385 } 9386 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9387 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9388 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9389 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9390 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9391 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9392 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9393 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]); 9394 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9395 } 9396 } 9397 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9398 if (p != pp) { 9399 storagecheck = PETSC_FALSE; 9400 continue; 9401 } 9402 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9403 PetscCall(DMPlexGetSupport(dm, p, &support)); 9404 for (s = 0; s < supportSize; ++s) { 9405 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9406 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9407 for (c = 0; c < coneSize; ++c) { 9408 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9409 if (cone[c] != pp) { 9410 c = 0; 9411 break; 9412 } 9413 if (cone[c] == p) break; 9414 } 9415 if (c >= coneSize) { 9416 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9417 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9418 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9419 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9420 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9421 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9422 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9423 } 9424 } 9425 } 9426 if (storagecheck) { 9427 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9428 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9429 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9430 } 9431 PetscFunctionReturn(PETSC_SUCCESS); 9432 } 9433 9434 /* 9435 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. 9436 */ 9437 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9438 { 9439 DMPolytopeType cct; 9440 PetscInt ptpoints[4]; 9441 const PetscInt *cone, *ccone, *ptcone; 9442 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9443 9444 PetscFunctionBegin; 9445 *unsplit = 0; 9446 switch (ct) { 9447 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9448 ptpoints[npt++] = c; 9449 break; 9450 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9451 PetscCall(DMPlexGetCone(dm, c, &cone)); 9452 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9453 for (cp = 0; cp < coneSize; ++cp) { 9454 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9455 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9456 } 9457 break; 9458 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9459 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9460 PetscCall(DMPlexGetCone(dm, c, &cone)); 9461 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9462 for (cp = 0; cp < coneSize; ++cp) { 9463 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9464 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9465 for (ccp = 0; ccp < cconeSize; ++ccp) { 9466 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9467 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9468 PetscInt p; 9469 for (p = 0; p < npt; ++p) 9470 if (ptpoints[p] == ccone[ccp]) break; 9471 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9472 } 9473 } 9474 } 9475 break; 9476 default: 9477 break; 9478 } 9479 for (pt = 0; pt < npt; ++pt) { 9480 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9481 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9482 } 9483 PetscFunctionReturn(PETSC_SUCCESS); 9484 } 9485 9486 /*@ 9487 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9488 9489 Input Parameters: 9490 + dm - The `DMPLEX` object 9491 - cellHeight - Normally 0 9492 9493 Level: developer 9494 9495 Notes: 9496 This is a useful diagnostic when creating meshes programmatically. 9497 Currently applicable only to homogeneous simplex or tensor meshes. 9498 9499 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9500 9501 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9502 @*/ 9503 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9504 { 9505 DMPlexInterpolatedFlag interp; 9506 DMPolytopeType ct; 9507 PetscInt vStart, vEnd, cStart, cEnd, c; 9508 9509 PetscFunctionBegin; 9510 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9511 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9512 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9513 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9514 for (c = cStart; c < cEnd; ++c) { 9515 PetscInt *closure = NULL; 9516 PetscInt coneSize, closureSize, cl, Nv = 0; 9517 9518 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9519 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9520 if (interp == DMPLEX_INTERPOLATED_FULL) { 9521 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9522 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)); 9523 } 9524 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9525 for (cl = 0; cl < closureSize * 2; cl += 2) { 9526 const PetscInt p = closure[cl]; 9527 if ((p >= vStart) && (p < vEnd)) ++Nv; 9528 } 9529 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9530 /* Special Case: Tensor faces with identified vertices */ 9531 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9532 PetscInt unsplit; 9533 9534 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9535 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9536 } 9537 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)); 9538 } 9539 PetscFunctionReturn(PETSC_SUCCESS); 9540 } 9541 9542 /*@ 9543 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9544 9545 Collective 9546 9547 Input Parameters: 9548 + dm - The `DMPLEX` object 9549 - cellHeight - Normally 0 9550 9551 Level: developer 9552 9553 Notes: 9554 This is a useful diagnostic when creating meshes programmatically. 9555 This routine is only relevant for meshes that are fully interpolated across all ranks. 9556 It will error out if a partially interpolated mesh is given on some rank. 9557 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9558 9559 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9560 9561 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9562 @*/ 9563 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9564 { 9565 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9566 DMPlexInterpolatedFlag interpEnum; 9567 9568 PetscFunctionBegin; 9569 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9570 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9571 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9572 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9573 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9574 PetscFunctionReturn(PETSC_SUCCESS); 9575 } 9576 9577 PetscCall(DMGetDimension(dm, &dim)); 9578 PetscCall(DMPlexGetDepth(dm, &depth)); 9579 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9580 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9581 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9582 for (c = cStart; c < cEnd; ++c) { 9583 const PetscInt *cone, *ornt, *faceSizes, *faces; 9584 const DMPolytopeType *faceTypes; 9585 DMPolytopeType ct; 9586 PetscInt numFaces, coneSize, f; 9587 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9588 9589 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9590 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9591 if (unsplit) continue; 9592 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9593 PetscCall(DMPlexGetCone(dm, c, &cone)); 9594 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9595 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9596 for (cl = 0; cl < closureSize * 2; cl += 2) { 9597 const PetscInt p = closure[cl]; 9598 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9599 } 9600 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9601 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); 9602 for (f = 0; f < numFaces; ++f) { 9603 DMPolytopeType fct; 9604 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9605 9606 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9607 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9608 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9609 const PetscInt p = fclosure[cl]; 9610 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9611 } 9612 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]); 9613 for (v = 0; v < fnumCorners; ++v) { 9614 if (fclosure[v] != faces[fOff + v]) { 9615 PetscInt v1; 9616 9617 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9618 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9619 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9620 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9621 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9622 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]); 9623 } 9624 } 9625 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9626 fOff += faceSizes[f]; 9627 } 9628 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9629 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9630 } 9631 } 9632 PetscFunctionReturn(PETSC_SUCCESS); 9633 } 9634 9635 /*@ 9636 DMPlexCheckGeometry - Check the geometry of mesh cells 9637 9638 Input Parameter: 9639 . dm - The `DMPLEX` object 9640 9641 Level: developer 9642 9643 Notes: 9644 This is a useful diagnostic when creating meshes programmatically. 9645 9646 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9647 9648 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9649 @*/ 9650 PetscErrorCode DMPlexCheckGeometry(DM dm) 9651 { 9652 Vec coordinates; 9653 PetscReal detJ, J[9], refVol = 1.0; 9654 PetscReal vol; 9655 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9656 9657 PetscFunctionBegin; 9658 PetscCall(DMGetDimension(dm, &dim)); 9659 PetscCall(DMGetCoordinateDim(dm, &dE)); 9660 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9661 PetscCall(DMPlexGetDepth(dm, &depth)); 9662 for (d = 0; d < dim; ++d) refVol *= 2.0; 9663 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9664 /* Make sure local coordinates are created, because that step is collective */ 9665 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9666 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9667 for (c = cStart; c < cEnd; ++c) { 9668 DMPolytopeType ct; 9669 PetscInt unsplit; 9670 PetscBool ignoreZeroVol = PETSC_FALSE; 9671 9672 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9673 switch (ct) { 9674 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9675 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9676 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9677 ignoreZeroVol = PETSC_TRUE; 9678 break; 9679 default: 9680 break; 9681 } 9682 switch (ct) { 9683 case DM_POLYTOPE_TRI_PRISM: 9684 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9685 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9686 case DM_POLYTOPE_PYRAMID: 9687 continue; 9688 default: 9689 break; 9690 } 9691 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9692 if (unsplit) continue; 9693 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9694 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); 9695 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9696 /* This should work with periodicity since DG coordinates should be used */ 9697 if (depth > 1) { 9698 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9699 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); 9700 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9701 } 9702 } 9703 PetscFunctionReturn(PETSC_SUCCESS); 9704 } 9705 9706 /*@ 9707 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9708 9709 Collective 9710 9711 Input Parameters: 9712 + dm - The `DMPLEX` object 9713 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9714 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9715 9716 Level: developer 9717 9718 Notes: 9719 This is mainly intended for debugging/testing purposes. 9720 9721 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9722 9723 Extra roots can come from periodic cuts, where additional points appear on the boundary 9724 9725 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9726 @*/ 9727 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9728 { 9729 PetscInt l, nleaves, nroots, overlap; 9730 const PetscInt *locals; 9731 const PetscSFNode *remotes; 9732 PetscBool distributed; 9733 MPI_Comm comm; 9734 PetscMPIInt rank; 9735 9736 PetscFunctionBegin; 9737 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9738 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9739 else pointSF = dm->sf; 9740 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9741 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9742 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9743 { 9744 PetscMPIInt mpiFlag; 9745 9746 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9747 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9748 } 9749 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9750 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9751 if (!distributed) { 9752 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); 9753 PetscFunctionReturn(PETSC_SUCCESS); 9754 } 9755 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); 9756 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9757 9758 /* Check SF graph is compatible with DMPlex chart */ 9759 { 9760 PetscInt pStart, pEnd, maxLeaf; 9761 9762 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9763 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9764 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9765 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9766 } 9767 9768 /* Check there are no cells in interface */ 9769 if (!overlap) { 9770 PetscInt cellHeight, cStart, cEnd; 9771 9772 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9773 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9774 for (l = 0; l < nleaves; ++l) { 9775 const PetscInt point = locals ? locals[l] : l; 9776 9777 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9778 } 9779 } 9780 9781 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9782 { 9783 const PetscInt *rootdegree; 9784 9785 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9786 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9787 for (l = 0; l < nleaves; ++l) { 9788 const PetscInt point = locals ? locals[l] : l; 9789 const PetscInt *cone; 9790 PetscInt coneSize, c, idx; 9791 9792 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9793 PetscCall(DMPlexGetCone(dm, point, &cone)); 9794 for (c = 0; c < coneSize; ++c) { 9795 if (!rootdegree[cone[c]]) { 9796 if (locals) { 9797 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9798 } else { 9799 idx = (cone[c] < nleaves) ? cone[c] : -1; 9800 } 9801 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9802 } 9803 } 9804 } 9805 } 9806 PetscFunctionReturn(PETSC_SUCCESS); 9807 } 9808 9809 /*@ 9810 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9811 9812 Collective 9813 9814 Input Parameter: 9815 . dm - The `DMPLEX` object 9816 9817 Level: developer 9818 9819 Notes: 9820 This is mainly intended for debugging/testing purposes. 9821 9822 Other cell types which are disconnected would be caught by the symmetry and face checks. 9823 9824 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9825 9826 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9827 @*/ 9828 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9829 { 9830 PetscInt pStart, pEnd, vStart, vEnd; 9831 9832 PetscFunctionBegin; 9833 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9834 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9835 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9836 for (PetscInt v = vStart; v < vEnd; ++v) { 9837 PetscInt suppSize; 9838 9839 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9840 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9841 } 9842 PetscFunctionReturn(PETSC_SUCCESS); 9843 } 9844 9845 /*@ 9846 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9847 9848 Input Parameter: 9849 . dm - The `DMPLEX` object 9850 9851 Level: developer 9852 9853 Notes: 9854 This is a useful diagnostic when creating meshes programmatically. 9855 9856 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9857 9858 Currently does not include `DMPlexCheckCellShape()`. 9859 9860 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9861 @*/ 9862 PetscErrorCode DMPlexCheck(DM dm) 9863 { 9864 PetscInt cellHeight; 9865 9866 PetscFunctionBegin; 9867 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9868 PetscCall(DMPlexCheckSymmetry(dm)); 9869 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9870 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9871 PetscCall(DMPlexCheckGeometry(dm)); 9872 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9873 PetscCall(DMPlexCheckInterfaceCones(dm)); 9874 PetscCall(DMPlexCheckOrphanVertices(dm)); 9875 PetscFunctionReturn(PETSC_SUCCESS); 9876 } 9877 9878 typedef struct cell_stats { 9879 PetscReal min, max, sum, squaresum; 9880 PetscInt count; 9881 } cell_stats_t; 9882 9883 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9884 { 9885 PetscInt i, N = *len; 9886 9887 for (i = 0; i < N; i++) { 9888 cell_stats_t *A = (cell_stats_t *)a; 9889 cell_stats_t *B = (cell_stats_t *)b; 9890 9891 B->min = PetscMin(A->min, B->min); 9892 B->max = PetscMax(A->max, B->max); 9893 B->sum += A->sum; 9894 B->squaresum += A->squaresum; 9895 B->count += A->count; 9896 } 9897 } 9898 9899 /*@ 9900 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9901 9902 Collective 9903 9904 Input Parameters: 9905 + dm - The `DMPLEX` object 9906 . output - If true, statistics will be displayed on `stdout` 9907 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9908 9909 Level: developer 9910 9911 Notes: 9912 This is mainly intended for debugging/testing purposes. 9913 9914 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9915 9916 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9917 @*/ 9918 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9919 { 9920 DM dmCoarse; 9921 cell_stats_t stats, globalStats; 9922 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9923 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9924 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9925 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9926 PetscMPIInt rank, size; 9927 9928 PetscFunctionBegin; 9929 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9930 stats.min = PETSC_MAX_REAL; 9931 stats.max = PETSC_MIN_REAL; 9932 stats.sum = stats.squaresum = 0.; 9933 stats.count = 0; 9934 9935 PetscCallMPI(MPI_Comm_size(comm, &size)); 9936 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9937 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9938 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9939 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9940 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9941 for (c = cStart; c < cEnd; c++) { 9942 PetscInt i; 9943 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9944 9945 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9946 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9947 for (i = 0; i < PetscSqr(cdim); ++i) { 9948 frobJ += J[i] * J[i]; 9949 frobInvJ += invJ[i] * invJ[i]; 9950 } 9951 cond2 = frobJ * frobInvJ; 9952 cond = PetscSqrtReal(cond2); 9953 9954 stats.min = PetscMin(stats.min, cond); 9955 stats.max = PetscMax(stats.max, cond); 9956 stats.sum += cond; 9957 stats.squaresum += cond2; 9958 stats.count++; 9959 if (output && cond > limit) { 9960 PetscSection coordSection; 9961 Vec coordsLocal; 9962 PetscScalar *coords = NULL; 9963 PetscInt Nv, d, clSize, cl, *closure = NULL; 9964 9965 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9966 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9967 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9968 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9969 for (i = 0; i < Nv / cdim; ++i) { 9970 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9971 for (d = 0; d < cdim; ++d) { 9972 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9973 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9974 } 9975 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9976 } 9977 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9978 for (cl = 0; cl < clSize * 2; cl += 2) { 9979 const PetscInt edge = closure[cl]; 9980 9981 if ((edge >= eStart) && (edge < eEnd)) { 9982 PetscReal len; 9983 9984 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9985 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9986 } 9987 } 9988 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9989 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9990 } 9991 } 9992 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9993 9994 if (size > 1) { 9995 PetscMPIInt blockLengths[2] = {4, 1}; 9996 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9997 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9998 MPI_Op statReduce; 9999 10000 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 10001 PetscCallMPI(MPI_Type_commit(&statType)); 10002 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 10003 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 10004 PetscCallMPI(MPI_Op_free(&statReduce)); 10005 PetscCallMPI(MPI_Type_free(&statType)); 10006 } else { 10007 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 10008 } 10009 if (rank == 0) { 10010 count = globalStats.count; 10011 min = globalStats.min; 10012 max = globalStats.max; 10013 mean = globalStats.sum / globalStats.count; 10014 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 10015 } 10016 10017 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)); 10018 PetscCall(PetscFree2(J, invJ)); 10019 10020 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 10021 if (dmCoarse) { 10022 PetscBool isplex; 10023 10024 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 10025 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 10026 } 10027 PetscFunctionReturn(PETSC_SUCCESS); 10028 } 10029 10030 /*@ 10031 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 10032 orthogonal quality below given tolerance. 10033 10034 Collective 10035 10036 Input Parameters: 10037 + dm - The `DMPLEX` object 10038 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 10039 - atol - [0, 1] Absolute tolerance for tagging cells. 10040 10041 Output Parameters: 10042 + OrthQual - `Vec` containing orthogonal quality per cell 10043 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 10044 10045 Options Database Keys: 10046 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 10047 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 10048 10049 Level: intermediate 10050 10051 Notes: 10052 Orthogonal quality is given by the following formula\: 10053 10054 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 10055 10056 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 10057 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 10058 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 10059 calculating the cosine of the angle between these vectors. 10060 10061 Orthogonal quality ranges from 1 (best) to 0 (worst). 10062 10063 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 10064 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 10065 10066 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 10067 10068 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 10069 @*/ 10070 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 10071 { 10072 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 10073 PetscInt *idx; 10074 PetscScalar *oqVals; 10075 const PetscScalar *cellGeomArr, *faceGeomArr; 10076 PetscReal *ci, *fi, *Ai; 10077 MPI_Comm comm; 10078 Vec cellgeom, facegeom; 10079 DM dmFace, dmCell; 10080 IS glob; 10081 ISLocalToGlobalMapping ltog; 10082 PetscViewer vwr; 10083 10084 PetscFunctionBegin; 10085 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10086 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 10087 PetscAssertPointer(OrthQual, 4); 10088 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 10089 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 10090 PetscCall(DMGetDimension(dm, &nc)); 10091 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 10092 { 10093 DMPlexInterpolatedFlag interpFlag; 10094 10095 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 10096 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 10097 PetscMPIInt rank; 10098 10099 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 10100 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 10101 } 10102 } 10103 if (OrthQualLabel) { 10104 PetscAssertPointer(OrthQualLabel, 5); 10105 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 10106 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 10107 } else { 10108 *OrthQualLabel = NULL; 10109 } 10110 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 10111 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 10112 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 10113 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 10114 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 10115 PetscCall(VecCreate(comm, OrthQual)); 10116 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 10117 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 10118 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 10119 PetscCall(VecSetUp(*OrthQual)); 10120 PetscCall(ISDestroy(&glob)); 10121 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 10122 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 10123 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 10124 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 10125 PetscCall(VecGetDM(cellgeom, &dmCell)); 10126 PetscCall(VecGetDM(facegeom, &dmFace)); 10127 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 10128 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 10129 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 10130 PetscInt cellarr[2], *adj = NULL; 10131 PetscScalar *cArr, *fArr; 10132 PetscReal minvalc = 1.0, minvalf = 1.0; 10133 PetscFVCellGeom *cg; 10134 10135 idx[cellIter] = cell - cStart; 10136 cellarr[0] = cell; 10137 /* Make indexing into cellGeom easier */ 10138 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10139 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10140 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10141 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10142 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10143 PetscInt i; 10144 const PetscInt neigh = adj[cellneigh]; 10145 PetscReal normci = 0, normfi = 0, normai = 0; 10146 PetscFVCellGeom *cgneigh; 10147 PetscFVFaceGeom *fg; 10148 10149 /* Don't count ourselves in the neighbor list */ 10150 if (neigh == cell) continue; 10151 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10152 cellarr[1] = neigh; 10153 { 10154 PetscInt numcovpts; 10155 const PetscInt *covpts; 10156 10157 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10158 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10159 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10160 } 10161 10162 /* Compute c_i, f_i and their norms */ 10163 for (i = 0; i < nc; i++) { 10164 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10165 fi[i] = fg->centroid[i] - cg->centroid[i]; 10166 Ai[i] = fg->normal[i]; 10167 normci += PetscPowReal(ci[i], 2); 10168 normfi += PetscPowReal(fi[i], 2); 10169 normai += PetscPowReal(Ai[i], 2); 10170 } 10171 normci = PetscSqrtReal(normci); 10172 normfi = PetscSqrtReal(normfi); 10173 normai = PetscSqrtReal(normai); 10174 10175 /* Normalize and compute for each face-cell-normal pair */ 10176 for (i = 0; i < nc; i++) { 10177 ci[i] = ci[i] / normci; 10178 fi[i] = fi[i] / normfi; 10179 Ai[i] = Ai[i] / normai; 10180 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10181 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10182 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10183 } 10184 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10185 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10186 } 10187 PetscCall(PetscFree(adj)); 10188 PetscCall(PetscFree2(cArr, fArr)); 10189 /* Defer to cell if they're equal */ 10190 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10191 if (OrthQualLabel) { 10192 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10193 } 10194 } 10195 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10196 PetscCall(VecAssemblyBegin(*OrthQual)); 10197 PetscCall(VecAssemblyEnd(*OrthQual)); 10198 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10199 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10200 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10201 if (OrthQualLabel) { 10202 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10203 } 10204 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10205 PetscCall(PetscViewerDestroy(&vwr)); 10206 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10207 PetscFunctionReturn(PETSC_SUCCESS); 10208 } 10209 10210 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10211 * interpolator construction */ 10212 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10213 { 10214 PetscSection section, newSection, gsection; 10215 PetscSF sf; 10216 PetscBool hasConstraints, ghasConstraints; 10217 10218 PetscFunctionBegin; 10219 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10220 PetscAssertPointer(odm, 2); 10221 PetscCall(DMGetLocalSection(dm, §ion)); 10222 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10223 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10224 if (!ghasConstraints) { 10225 PetscCall(PetscObjectReference((PetscObject)dm)); 10226 *odm = dm; 10227 PetscFunctionReturn(PETSC_SUCCESS); 10228 } 10229 PetscCall(DMClone(dm, odm)); 10230 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10231 PetscCall(DMGetLocalSection(*odm, &newSection)); 10232 PetscCall(DMGetPointSF(*odm, &sf)); 10233 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10234 PetscCall(DMSetGlobalSection(*odm, gsection)); 10235 PetscCall(PetscSectionDestroy(&gsection)); 10236 PetscFunctionReturn(PETSC_SUCCESS); 10237 } 10238 10239 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10240 { 10241 DM dmco, dmfo; 10242 Mat interpo; 10243 Vec rscale; 10244 Vec cglobalo, clocal; 10245 Vec fglobal, fglobalo, flocal; 10246 PetscBool regular; 10247 10248 PetscFunctionBegin; 10249 PetscCall(DMGetFullDM(dmc, &dmco)); 10250 PetscCall(DMGetFullDM(dmf, &dmfo)); 10251 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10252 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10253 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10254 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10255 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10256 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10257 PetscCall(VecSet(cglobalo, 0.)); 10258 PetscCall(VecSet(clocal, 0.)); 10259 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10260 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10261 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10262 PetscCall(VecSet(fglobal, 0.)); 10263 PetscCall(VecSet(fglobalo, 0.)); 10264 PetscCall(VecSet(flocal, 0.)); 10265 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10266 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10267 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10268 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10269 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10270 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10271 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10272 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10273 *shift = fglobal; 10274 PetscCall(VecDestroy(&flocal)); 10275 PetscCall(VecDestroy(&fglobalo)); 10276 PetscCall(VecDestroy(&clocal)); 10277 PetscCall(VecDestroy(&cglobalo)); 10278 PetscCall(VecDestroy(&rscale)); 10279 PetscCall(MatDestroy(&interpo)); 10280 PetscCall(DMDestroy(&dmfo)); 10281 PetscCall(DMDestroy(&dmco)); 10282 PetscFunctionReturn(PETSC_SUCCESS); 10283 } 10284 10285 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10286 { 10287 PetscObject shifto; 10288 Vec shift; 10289 10290 PetscFunctionBegin; 10291 if (!interp) { 10292 Vec rscale; 10293 10294 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10295 PetscCall(VecDestroy(&rscale)); 10296 } else { 10297 PetscCall(PetscObjectReference((PetscObject)interp)); 10298 } 10299 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10300 if (!shifto) { 10301 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10302 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10303 shifto = (PetscObject)shift; 10304 PetscCall(VecDestroy(&shift)); 10305 } 10306 shift = (Vec)shifto; 10307 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10308 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10309 PetscCall(MatDestroy(&interp)); 10310 PetscFunctionReturn(PETSC_SUCCESS); 10311 } 10312 10313 /* Pointwise interpolation 10314 Just code FEM for now 10315 u^f = I u^c 10316 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10317 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10318 I_{ij} = psi^f_i phi^c_j 10319 */ 10320 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10321 { 10322 PetscSection gsc, gsf; 10323 PetscInt m, n; 10324 void *ctx; 10325 DM cdm; 10326 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10327 10328 PetscFunctionBegin; 10329 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10330 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10331 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10332 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10333 10334 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10335 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10336 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10337 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10338 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10339 10340 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10341 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10342 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10343 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10344 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10345 if (scaling) { 10346 /* Use naive scaling */ 10347 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10348 } 10349 PetscFunctionReturn(PETSC_SUCCESS); 10350 } 10351 10352 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10353 { 10354 VecScatter ctx; 10355 10356 PetscFunctionBegin; 10357 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10358 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10359 PetscCall(VecScatterDestroy(&ctx)); 10360 PetscFunctionReturn(PETSC_SUCCESS); 10361 } 10362 10363 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[]) 10364 { 10365 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10366 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10367 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10368 } 10369 10370 // The assumption here is that the test field is a vector and the basis field is a scalar (so we need the gradient) 10371 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[]) 10372 { 10373 for (PetscInt c = 0; c < dim; ++c) g1[c * dim + c] = 1.0; 10374 } 10375 10376 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10377 { 10378 DM dmc; 10379 PetscDS ds; 10380 Vec ones, locmass; 10381 IS cellIS; 10382 PetscFormKey key; 10383 PetscInt depth; 10384 10385 PetscFunctionBegin; 10386 PetscCall(DMClone(dm, &dmc)); 10387 PetscCall(DMCopyDisc(dm, dmc)); 10388 PetscCall(DMGetDS(dmc, &ds)); 10389 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10390 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10391 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10392 else PetscCall(DMGetLocalVector(dm, &locmass)); 10393 PetscCall(DMGetLocalVector(dm, &ones)); 10394 PetscCall(DMPlexGetDepth(dm, &depth)); 10395 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10396 PetscCall(VecSet(locmass, 0.0)); 10397 PetscCall(VecSet(ones, 1.0)); 10398 key.label = NULL; 10399 key.value = 0; 10400 key.field = 0; 10401 key.part = 0; 10402 PetscCall(DMPlexComputeJacobianActionByKey(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10403 PetscCall(ISDestroy(&cellIS)); 10404 if (mass) { 10405 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10406 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10407 } 10408 PetscCall(DMRestoreLocalVector(dm, &ones)); 10409 if (lmass) *lmass = locmass; 10410 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10411 PetscCall(DMDestroy(&dmc)); 10412 PetscFunctionReturn(PETSC_SUCCESS); 10413 } 10414 10415 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10416 { 10417 PetscSection gsc, gsf; 10418 PetscInt m, n; 10419 void *ctx; 10420 DM cdm; 10421 PetscBool regular; 10422 10423 PetscFunctionBegin; 10424 if (dmFine == dmCoarse) { 10425 DM dmc; 10426 PetscDS ds; 10427 PetscWeakForm wf; 10428 Vec u; 10429 IS cellIS; 10430 PetscFormKey key; 10431 PetscInt depth; 10432 10433 PetscCall(DMClone(dmFine, &dmc)); 10434 PetscCall(DMCopyDisc(dmFine, dmc)); 10435 PetscCall(DMGetDS(dmc, &ds)); 10436 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10437 PetscCall(PetscWeakFormClear(wf)); 10438 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10439 PetscCall(DMCreateMatrix(dmc, mass)); 10440 PetscCall(DMGetLocalVector(dmc, &u)); 10441 PetscCall(DMPlexGetDepth(dmc, &depth)); 10442 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10443 PetscCall(MatZeroEntries(*mass)); 10444 key.label = NULL; 10445 key.value = 0; 10446 key.field = 0; 10447 key.part = 0; 10448 PetscCall(DMPlexComputeJacobianByKey(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10449 PetscCall(ISDestroy(&cellIS)); 10450 PetscCall(DMRestoreLocalVector(dmc, &u)); 10451 PetscCall(DMDestroy(&dmc)); 10452 } else { 10453 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10454 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10455 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10456 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10457 10458 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10459 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10460 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10461 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10462 10463 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10464 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10465 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10466 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10467 } 10468 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10469 PetscFunctionReturn(PETSC_SUCCESS); 10470 } 10471 10472 PetscErrorCode DMCreateGradientMatrix_Plex(DM dmc, DM dmr, Mat *derv) 10473 { 10474 PetscSection gsc, gsf; 10475 PetscInt m, n; 10476 void *ctx; 10477 10478 PetscFunctionBegin; 10479 PetscCall(DMGetGlobalSection(dmr, &gsf)); 10480 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10481 PetscCall(DMGetGlobalSection(dmc, &gsc)); 10482 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10483 10484 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmc), derv)); 10485 PetscCall(PetscObjectSetName((PetscObject)*derv, "Plex Derivative Matrix")); 10486 PetscCall(MatSetSizes(*derv, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10487 PetscCall(MatSetType(*derv, dmc->mattype)); 10488 10489 PetscCall(DMGetApplicationContext(dmr, &ctx)); 10490 { 10491 DM ndmr; 10492 PetscDS ds; 10493 PetscWeakForm wf; 10494 Vec u; 10495 IS cellIS; 10496 PetscFormKey key; 10497 PetscInt depth, Nf; 10498 10499 PetscCall(DMClone(dmr, &ndmr)); 10500 PetscCall(DMCopyDisc(dmr, ndmr)); 10501 PetscCall(DMGetDS(ndmr, &ds)); 10502 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10503 PetscCall(PetscWeakFormClear(wf)); 10504 PetscCall(PetscDSGetNumFields(ds, &Nf)); 10505 for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, NULL, g1_identity_private, NULL, NULL)); 10506 PetscCall(DMGetLocalVector(ndmr, &u)); 10507 PetscCall(DMPlexGetDepth(ndmr, &depth)); 10508 PetscCall(DMGetStratumIS(ndmr, "depth", depth, &cellIS)); 10509 PetscCall(MatZeroEntries(*derv)); 10510 key.label = NULL; 10511 key.value = 0; 10512 key.field = 0; 10513 key.part = 0; 10514 PetscCall(DMPlexComputeJacobianByKeyGeneral(ndmr, dmc, key, cellIS, 0.0, 0.0, u, NULL, *derv, *derv, NULL)); 10515 PetscCall(ISDestroy(&cellIS)); 10516 PetscCall(DMRestoreLocalVector(ndmr, &u)); 10517 PetscCall(DMDestroy(&ndmr)); 10518 } 10519 PetscCall(MatViewFromOptions(*derv, NULL, "-gradient_mat_view")); 10520 PetscFunctionReturn(PETSC_SUCCESS); 10521 } 10522 10523 /*@ 10524 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10525 10526 Input Parameter: 10527 . dm - The `DMPLEX` object 10528 10529 Output Parameter: 10530 . regular - The flag 10531 10532 Level: intermediate 10533 10534 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10535 @*/ 10536 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10537 { 10538 PetscFunctionBegin; 10539 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10540 PetscAssertPointer(regular, 2); 10541 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10542 PetscFunctionReturn(PETSC_SUCCESS); 10543 } 10544 10545 /*@ 10546 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10547 10548 Input Parameters: 10549 + dm - The `DMPLEX` object 10550 - regular - The flag 10551 10552 Level: intermediate 10553 10554 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10555 @*/ 10556 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10557 { 10558 PetscFunctionBegin; 10559 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10560 ((DM_Plex *)dm->data)->regularRefinement = regular; 10561 PetscFunctionReturn(PETSC_SUCCESS); 10562 } 10563 10564 /*@ 10565 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10566 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10567 10568 Not Collective 10569 10570 Input Parameter: 10571 . dm - The `DMPLEX` object 10572 10573 Output Parameters: 10574 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10575 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10576 10577 Level: intermediate 10578 10579 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10580 @*/ 10581 PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS) 10582 { 10583 DM_Plex *plex = (DM_Plex *)dm->data; 10584 10585 PetscFunctionBegin; 10586 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10587 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10588 if (anchorSection) *anchorSection = plex->anchorSection; 10589 if (anchorIS) *anchorIS = plex->anchorIS; 10590 PetscFunctionReturn(PETSC_SUCCESS); 10591 } 10592 10593 /*@ 10594 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10595 10596 Collective 10597 10598 Input Parameters: 10599 + dm - The `DMPLEX` object 10600 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10601 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10602 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10603 10604 Level: intermediate 10605 10606 Notes: 10607 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10608 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10609 combination of other points' degrees of freedom. 10610 10611 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10612 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10613 10614 The reference counts of `anchorSection` and `anchorIS` are incremented. 10615 10616 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10617 @*/ 10618 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10619 { 10620 DM_Plex *plex = (DM_Plex *)dm->data; 10621 PetscMPIInt result; 10622 10623 PetscFunctionBegin; 10624 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10625 if (anchorSection) { 10626 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10627 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10628 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10629 } 10630 if (anchorIS) { 10631 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10632 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10633 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10634 } 10635 10636 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10637 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10638 plex->anchorSection = anchorSection; 10639 10640 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10641 PetscCall(ISDestroy(&plex->anchorIS)); 10642 plex->anchorIS = anchorIS; 10643 10644 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10645 PetscInt size, a, pStart, pEnd; 10646 const PetscInt *anchors; 10647 10648 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10649 PetscCall(ISGetLocalSize(anchorIS, &size)); 10650 PetscCall(ISGetIndices(anchorIS, &anchors)); 10651 for (a = 0; a < size; a++) { 10652 PetscInt p; 10653 10654 p = anchors[a]; 10655 if (p >= pStart && p < pEnd) { 10656 PetscInt dof; 10657 10658 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10659 if (dof) { 10660 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10661 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10662 } 10663 } 10664 } 10665 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10666 } 10667 /* reset the generic constraints */ 10668 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10669 PetscFunctionReturn(PETSC_SUCCESS); 10670 } 10671 10672 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10673 { 10674 PetscSection anchorSection; 10675 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10676 10677 PetscFunctionBegin; 10678 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10679 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10680 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10681 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10682 if (numFields) { 10683 PetscInt f; 10684 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10685 10686 for (f = 0; f < numFields; f++) { 10687 PetscInt numComp; 10688 10689 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10690 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10691 } 10692 } 10693 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10694 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10695 pStart = PetscMax(pStart, sStart); 10696 pEnd = PetscMin(pEnd, sEnd); 10697 pEnd = PetscMax(pStart, pEnd); 10698 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10699 for (p = pStart; p < pEnd; p++) { 10700 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10701 if (dof) { 10702 PetscCall(PetscSectionGetDof(section, p, &dof)); 10703 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10704 for (f = 0; f < numFields; f++) { 10705 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10706 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10707 } 10708 } 10709 } 10710 PetscCall(PetscSectionSetUp(*cSec)); 10711 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10712 PetscFunctionReturn(PETSC_SUCCESS); 10713 } 10714 10715 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10716 { 10717 PetscSection aSec; 10718 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10719 const PetscInt *anchors; 10720 PetscInt numFields, f; 10721 IS aIS; 10722 MatType mtype; 10723 PetscBool iscuda, iskokkos; 10724 10725 PetscFunctionBegin; 10726 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10727 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10728 PetscCall(PetscSectionGetStorageSize(section, &n)); 10729 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10730 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10731 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10732 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10733 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10734 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10735 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10736 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10737 else mtype = MATSEQAIJ; 10738 PetscCall(MatSetType(*cMat, mtype)); 10739 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10740 PetscCall(ISGetIndices(aIS, &anchors)); 10741 /* cSec will be a subset of aSec and section */ 10742 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10743 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10744 PetscCall(PetscMalloc1(m + 1, &i)); 10745 i[0] = 0; 10746 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10747 for (p = pStart; p < pEnd; p++) { 10748 PetscInt rDof, rOff, r; 10749 10750 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10751 if (!rDof) continue; 10752 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10753 if (numFields) { 10754 for (f = 0; f < numFields; f++) { 10755 annz = 0; 10756 for (r = 0; r < rDof; r++) { 10757 a = anchors[rOff + r]; 10758 if (a < sStart || a >= sEnd) continue; 10759 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10760 annz += aDof; 10761 } 10762 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10763 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10764 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10765 } 10766 } else { 10767 annz = 0; 10768 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10769 for (q = 0; q < dof; q++) { 10770 a = anchors[rOff + q]; 10771 if (a < sStart || a >= sEnd) continue; 10772 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10773 annz += aDof; 10774 } 10775 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10776 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10777 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10778 } 10779 } 10780 nnz = i[m]; 10781 PetscCall(PetscMalloc1(nnz, &j)); 10782 offset = 0; 10783 for (p = pStart; p < pEnd; p++) { 10784 if (numFields) { 10785 for (f = 0; f < numFields; f++) { 10786 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10787 for (q = 0; q < dof; q++) { 10788 PetscInt rDof, rOff, r; 10789 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10790 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10791 for (r = 0; r < rDof; r++) { 10792 PetscInt s; 10793 10794 a = anchors[rOff + r]; 10795 if (a < sStart || a >= sEnd) continue; 10796 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10797 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10798 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10799 } 10800 } 10801 } 10802 } else { 10803 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10804 for (q = 0; q < dof; q++) { 10805 PetscInt rDof, rOff, r; 10806 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10807 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10808 for (r = 0; r < rDof; r++) { 10809 PetscInt s; 10810 10811 a = anchors[rOff + r]; 10812 if (a < sStart || a >= sEnd) continue; 10813 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10814 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10815 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10816 } 10817 } 10818 } 10819 } 10820 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10821 PetscCall(PetscFree(i)); 10822 PetscCall(PetscFree(j)); 10823 PetscCall(ISRestoreIndices(aIS, &anchors)); 10824 PetscFunctionReturn(PETSC_SUCCESS); 10825 } 10826 10827 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10828 { 10829 DM_Plex *plex = (DM_Plex *)dm->data; 10830 PetscSection anchorSection, section, cSec; 10831 Mat cMat; 10832 10833 PetscFunctionBegin; 10834 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10835 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10836 if (anchorSection) { 10837 PetscInt Nf; 10838 10839 PetscCall(DMGetLocalSection(dm, §ion)); 10840 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10841 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10842 PetscCall(DMGetNumFields(dm, &Nf)); 10843 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10844 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10845 PetscCall(PetscSectionDestroy(&cSec)); 10846 PetscCall(MatDestroy(&cMat)); 10847 } 10848 PetscFunctionReturn(PETSC_SUCCESS); 10849 } 10850 10851 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10852 { 10853 IS subis; 10854 PetscSection section, subsection; 10855 10856 PetscFunctionBegin; 10857 PetscCall(DMGetLocalSection(dm, §ion)); 10858 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10859 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10860 /* Create subdomain */ 10861 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10862 /* Create submodel */ 10863 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10864 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10865 PetscCall(DMSetLocalSection(*subdm, subsection)); 10866 PetscCall(PetscSectionDestroy(&subsection)); 10867 PetscCall(DMCopyDisc(dm, *subdm)); 10868 /* Create map from submodel to global model */ 10869 if (is) { 10870 PetscSection sectionGlobal, subsectionGlobal; 10871 IS spIS; 10872 const PetscInt *spmap; 10873 PetscInt *subIndices; 10874 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10875 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10876 10877 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10878 PetscCall(ISGetIndices(spIS, &spmap)); 10879 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10880 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10881 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10882 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10883 for (p = pStart; p < pEnd; ++p) { 10884 PetscInt gdof, pSubSize = 0; 10885 10886 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10887 if (gdof > 0) { 10888 for (f = 0; f < Nf; ++f) { 10889 PetscInt fdof, fcdof; 10890 10891 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10892 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10893 pSubSize += fdof - fcdof; 10894 } 10895 subSize += pSubSize; 10896 if (pSubSize) { 10897 if (bs < 0) { 10898 bs = pSubSize; 10899 } else if (bs != pSubSize) { 10900 /* Layout does not admit a pointwise block size */ 10901 bs = 1; 10902 } 10903 } 10904 } 10905 } 10906 /* Must have same blocksize on all procs (some might have no points) */ 10907 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10908 bsLocal[1] = bs; 10909 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10910 if (bsMinMax[0] != bsMinMax[1]) { 10911 bs = 1; 10912 } else { 10913 bs = bsMinMax[0]; 10914 } 10915 PetscCall(PetscMalloc1(subSize, &subIndices)); 10916 for (p = pStart; p < pEnd; ++p) { 10917 PetscInt gdof, goff; 10918 10919 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10920 if (gdof > 0) { 10921 const PetscInt point = spmap[p]; 10922 10923 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10924 for (f = 0; f < Nf; ++f) { 10925 PetscInt fdof, fcdof, fc, f2, poff = 0; 10926 10927 /* Can get rid of this loop by storing field information in the global section */ 10928 for (f2 = 0; f2 < f; ++f2) { 10929 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10930 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10931 poff += fdof - fcdof; 10932 } 10933 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10934 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10935 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10936 } 10937 } 10938 } 10939 PetscCall(ISRestoreIndices(spIS, &spmap)); 10940 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10941 if (bs > 1) { 10942 /* We need to check that the block size does not come from non-contiguous fields */ 10943 PetscInt i, j, set = 1; 10944 for (i = 0; i < subSize; i += bs) { 10945 for (j = 0; j < bs; ++j) { 10946 if (subIndices[i + j] != subIndices[i] + j) { 10947 set = 0; 10948 break; 10949 } 10950 } 10951 } 10952 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10953 } 10954 // Attach nullspace 10955 if (dm->nullspaceConstructors) { 10956 for (f = 0; f < Nf; ++f) { 10957 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10958 if ((*subdm)->nullspaceConstructors[f]) break; 10959 } 10960 if (f < Nf) { 10961 MatNullSpace nullSpace; 10962 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10963 10964 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10965 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10966 } 10967 } 10968 } 10969 PetscFunctionReturn(PETSC_SUCCESS); 10970 } 10971 10972 /*@ 10973 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10974 10975 Input Parameters: 10976 + dm - The `DM` 10977 - dummy - unused argument 10978 10979 Options Database Key: 10980 . -dm_plex_monitor_throughput - Activate the monitor 10981 10982 Level: developer 10983 10984 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10985 @*/ 10986 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10987 { 10988 PetscLogHandler default_handler; 10989 10990 PetscFunctionBegin; 10991 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10992 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10993 if (default_handler) { 10994 PetscLogEvent event; 10995 PetscEventPerfInfo eventInfo; 10996 PetscLogDouble cellRate, flopRate; 10997 PetscInt cStart, cEnd, Nf, N; 10998 const char *name; 10999 11000 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 11001 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 11002 PetscCall(DMGetNumFields(dm, &Nf)); 11003 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 11004 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 11005 N = (cEnd - cStart) * Nf * eventInfo.count; 11006 flopRate = eventInfo.flops / eventInfo.time; 11007 cellRate = N / eventInfo.time; 11008 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)); 11009 } else { 11010 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."); 11011 } 11012 PetscFunctionReturn(PETSC_SUCCESS); 11013 } 11014