1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_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_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 PetscBool Plexcite = PETSC_FALSE; 18 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 19 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 20 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 21 "journal = {SIAM Journal on Scientific Computing},\n" 22 "volume = {38},\n" 23 "number = {5},\n" 24 "pages = {S143--S155},\n" 25 "eprint = {http://arxiv.org/abs/1506.07749},\n" 26 "doi = {10.1137/15M1026092},\n" 27 "year = {2016},\n" 28 "petsc_uses={DMPlex},\n}\n"; 29 30 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 31 32 /*@ 33 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 34 35 Input Parameter: 36 . dm - The `DMPLEX` object 37 38 Output Parameter: 39 . simplex - Flag checking for a simplex 40 41 Level: intermediate 42 43 Note: 44 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 45 If the mesh has no cells, this returns `PETSC_FALSE`. 46 47 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 48 @*/ 49 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 50 { 51 DMPolytopeType ct; 52 PetscInt cStart, cEnd; 53 54 PetscFunctionBegin; 55 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 56 if (cEnd <= cStart) { 57 *simplex = PETSC_FALSE; 58 PetscFunctionReturn(PETSC_SUCCESS); 59 } 60 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 61 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 62 PetscFunctionReturn(PETSC_SUCCESS); 63 } 64 65 /*@ 66 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 67 68 Input Parameters: 69 + dm - The `DMPLEX` object 70 - height - The cell height in the Plex, 0 is the default 71 72 Output Parameters: 73 + cStart - The first "normal" cell 74 - cEnd - The upper bound on "normal" cells 75 76 Level: developer 77 78 Note: 79 This function requires that tensor cells are ordered last. 80 81 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 82 @*/ 83 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 84 { 85 DMLabel ctLabel; 86 IS valueIS; 87 const PetscInt *ctypes; 88 PetscBool found = PETSC_FALSE; 89 PetscInt Nct, cS = PETSC_INT_MAX, cE = 0; 90 91 PetscFunctionBegin; 92 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 93 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 94 PetscCall(ISGetLocalSize(valueIS, &Nct)); 95 PetscCall(ISGetIndices(valueIS, &ctypes)); 96 for (PetscInt t = 0; t < Nct; ++t) { 97 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 98 PetscInt ctS, ctE, ht; 99 100 if (ct == DM_POLYTOPE_UNKNOWN) { 101 // If any cells are not typed, just use all cells 102 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 103 break; 104 } 105 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 106 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 107 if (ctS >= ctE) continue; 108 // Check that a point has the right height 109 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 110 if (ht != height) continue; 111 cS = PetscMin(cS, ctS); 112 cE = PetscMax(cE, ctE); 113 found = PETSC_TRUE; 114 } 115 if (!Nct || !found) cS = cE = 0; 116 PetscCall(ISDestroy(&valueIS)); 117 // Reset label for fast lookup 118 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 119 if (cStart) *cStart = cS; 120 if (cEnd) *cEnd = cE; 121 PetscFunctionReturn(PETSC_SUCCESS); 122 } 123 124 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 125 { 126 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 127 PetscInt *sStart, *sEnd; 128 PetscViewerVTKFieldType *ft; 129 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 130 DMLabel depthLabel, ctLabel; 131 132 PetscFunctionBegin; 133 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 134 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 135 PetscCall(DMGetCoordinateDim(dm, &cdim)); 136 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 137 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 138 if (field >= 0) { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 140 } else { 141 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 142 } 143 144 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 145 PetscCall(DMPlexGetDepth(dm, &depth)); 146 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 147 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 148 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 149 const DMPolytopeType ict = (DMPolytopeType)c; 150 PetscInt dep; 151 152 if (ict == DM_POLYTOPE_FV_GHOST) continue; 153 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 154 if (pStart >= 0) { 155 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 156 if (dep != depth - cellHeight) continue; 157 } 158 if (field >= 0) { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 160 } else { 161 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 162 } 163 } 164 165 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 166 *types = 0; 167 168 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 169 if (globalvcdof[c]) ++(*types); 170 } 171 172 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 173 t = 0; 174 if (globalvcdof[DM_NUM_POLYTOPES]) { 175 sStart[t] = vStart; 176 sEnd[t] = vEnd; 177 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 178 ++t; 179 } 180 181 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 182 if (globalvcdof[c]) { 183 const DMPolytopeType ict = (DMPolytopeType)c; 184 185 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 186 sStart[t] = cStart; 187 sEnd[t] = cEnd; 188 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 189 ++t; 190 } 191 } 192 193 if (!*types) { 194 if (field >= 0) { 195 const char *fieldname; 196 197 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 198 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 199 } else { 200 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 201 } 202 } 203 204 *ssStart = sStart; 205 *ssEnd = sEnd; 206 *sft = ft; 207 PetscFunctionReturn(PETSC_SUCCESS); 208 } 209 210 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 211 { 212 PetscFunctionBegin; 213 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 214 PetscFunctionReturn(PETSC_SUCCESS); 215 } 216 217 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 218 { 219 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 220 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 221 222 PetscFunctionBegin; 223 *ft = PETSC_VTK_INVALID; 224 PetscCall(DMGetCoordinateDim(dm, &cdim)); 225 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 226 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 227 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 228 if (field >= 0) { 229 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 230 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 231 } else { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 234 } 235 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 236 if (globalvcdof[0]) { 237 *sStart = vStart; 238 *sEnd = vEnd; 239 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 240 else *ft = PETSC_VTK_POINT_FIELD; 241 } else if (globalvcdof[1]) { 242 *sStart = cStart; 243 *sEnd = cEnd; 244 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 245 else *ft = PETSC_VTK_CELL_FIELD; 246 } else { 247 if (field >= 0) { 248 const char *fieldname; 249 250 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 251 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 252 } else { 253 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n")); 254 } 255 } 256 PetscFunctionReturn(PETSC_SUCCESS); 257 } 258 259 /*@ 260 DMPlexVecView1D - Plot many 1D solutions on the same line graph 261 262 Collective 263 264 Input Parameters: 265 + dm - The `DMPLEX` object 266 . n - The number of vectors 267 . u - The array of local vectors 268 - viewer - The `PetscViewer` 269 270 Level: advanced 271 272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 273 @*/ 274 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 275 { 276 DM cdm; 277 PetscDS ds; 278 PetscDraw draw = NULL; 279 PetscDrawLG lg; 280 Vec coordinates; 281 const PetscScalar *coords, **sol; 282 PetscReal *vals; 283 PetscInt *Nc; 284 PetscInt Nf, Nl, vStart, vEnd, eStart, eEnd; 285 char **names; 286 287 PetscFunctionBegin; 288 PetscCall(DMGetCoordinateDM(dm, &cdm)); 289 PetscCall(DMGetDS(dm, &ds)); 290 PetscCall(PetscDSGetNumFields(ds, &Nf)); 291 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 292 PetscCall(PetscDSGetComponents(ds, &Nc)); 293 294 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 295 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 296 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 297 298 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 299 for (PetscInt i = 0, l = 0; i < n; ++i) { 300 const char *vname; 301 302 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 303 for (PetscInt f = 0; f < Nf; ++f) { 304 PetscObject disc; 305 const char *fname; 306 char tmpname[PETSC_MAX_PATH_LEN]; 307 308 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 309 /* TODO Create names for components */ 310 for (PetscInt c = 0; c < Nc[f]; ++c, ++l) { 311 PetscCall(PetscObjectGetName(disc, &fname)); 312 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 313 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 314 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 315 PetscCall(PetscStrallocpy(tmpname, &names[l])); 316 } 317 } 318 } 319 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 320 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 321 PetscCall(VecGetArrayRead(coordinates, &coords)); 322 for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 323 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 324 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 325 PetscSection s; 326 PetscInt cdof, vdof; 327 328 PetscCall(DMGetLocalSection(dm, &s)); 329 PetscCall(PetscSectionGetDof(s, eStart, &cdof)); 330 PetscCall(PetscSectionGetDof(s, vStart, &vdof)); 331 if (cdof) { 332 if (vdof) { 333 // P_2 334 PetscInt vFirst = -1; 335 336 for (PetscInt e = eStart; e < eEnd; ++e) { 337 PetscScalar *xa, *xb, *svals; 338 const PetscInt *cone; 339 340 PetscCall(DMPlexGetCone(dm, e, &cone)); 341 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 342 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 343 if (e == eStart) vFirst = cone[0]; 344 for (PetscInt i = 0; i < n; ++i) { 345 PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals)); 346 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 347 } 348 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals)); 349 if (e == eEnd - 1 && cone[1] != vFirst) { 350 for (PetscInt i = 0; i < n; ++i) { 351 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 352 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 353 } 354 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 355 for (PetscInt i = 0; i < n; ++i) { 356 PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals)); 357 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 358 } 359 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals)); 360 } 361 } 362 } else { 363 // P_0 364 for (PetscInt e = eStart; e < eEnd; ++e) { 365 PetscScalar *xa, *xb, *svals; 366 const PetscInt *cone; 367 368 PetscCall(DMPlexGetCone(dm, e, &cone)); 369 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 370 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 371 for (PetscInt i = 0; i < n; ++i) { 372 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 373 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 374 } 375 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 376 } 377 } 378 } else if (vdof) { 379 // P_1 380 for (PetscInt v = vStart; v < vEnd; ++v) { 381 PetscScalar *x, *svals; 382 383 PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x)); 384 for (PetscInt i = 0; i < n; ++i) { 385 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 386 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 387 } 388 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 389 } 390 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Discretization not supported"); 391 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 392 for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 393 for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 394 PetscCall(PetscFree3(sol, names, vals)); 395 396 PetscCall(PetscDrawLGDraw(lg)); 397 PetscCall(PetscDrawLGDestroy(&lg)); 398 PetscFunctionReturn(PETSC_SUCCESS); 399 } 400 401 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 402 { 403 DM dm; 404 405 PetscFunctionBegin; 406 PetscCall(VecGetDM(u, &dm)); 407 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 408 PetscFunctionReturn(PETSC_SUCCESS); 409 } 410 411 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 412 { 413 DM dm; 414 PetscSection s; 415 PetscDraw draw, popup; 416 DM cdm; 417 PetscSection coordSection; 418 Vec coordinates; 419 const PetscScalar *array; 420 PetscReal lbound[3], ubound[3]; 421 PetscReal vbound[2], time; 422 PetscBool flg; 423 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 424 const char *name; 425 char title[PETSC_MAX_PATH_LEN]; 426 427 PetscFunctionBegin; 428 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 429 PetscCall(VecGetDM(v, &dm)); 430 PetscCall(DMGetCoordinateDim(dm, &dim)); 431 PetscCall(DMGetLocalSection(dm, &s)); 432 PetscCall(PetscSectionGetNumFields(s, &Nf)); 433 PetscCall(DMGetCoarsenLevel(dm, &level)); 434 PetscCall(DMGetCoordinateDM(dm, &cdm)); 435 PetscCall(DMGetLocalSection(cdm, &coordSection)); 436 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 437 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 438 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 439 440 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 441 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 442 443 PetscCall(VecGetLocalSize(coordinates, &N)); 444 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 445 PetscCall(PetscDrawClear(draw)); 446 447 /* Could implement something like DMDASelectFields() */ 448 for (f = 0; f < Nf; ++f) { 449 DM fdm = dm; 450 Vec fv = v; 451 IS fis; 452 char prefix[PETSC_MAX_PATH_LEN]; 453 const char *fname; 454 455 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 456 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 457 458 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 459 else prefix[0] = '\0'; 460 if (Nf > 1) { 461 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 462 PetscCall(VecGetSubVector(v, fis, &fv)); 463 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 464 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 465 } 466 for (comp = 0; comp < Nc; ++comp, ++w) { 467 PetscInt nmax = 2; 468 469 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 470 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 471 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 472 PetscCall(PetscDrawSetTitle(draw, title)); 473 474 /* TODO Get max and min only for this component */ 475 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 476 if (!flg) { 477 PetscCall(VecMin(fv, NULL, &vbound[0])); 478 PetscCall(VecMax(fv, NULL, &vbound[1])); 479 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 480 } 481 482 PetscCall(PetscDrawGetPopup(draw, &popup)); 483 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 484 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 485 PetscCall(VecGetArrayRead(fv, &array)); 486 for (c = cStart; c < cEnd; ++c) { 487 DMPolytopeType ct; 488 PetscScalar *coords = NULL, *a = NULL; 489 const PetscScalar *coords_arr; 490 PetscBool isDG; 491 PetscInt numCoords; 492 int color[4] = {-1, -1, -1, -1}; 493 494 PetscCall(DMPlexGetCellType(dm, c, &ct)); 495 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 496 if (a) { 497 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 498 color[1] = color[2] = color[3] = color[0]; 499 } else { 500 PetscScalar *vals = NULL; 501 PetscInt numVals, va; 502 503 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 504 if (!numVals) { 505 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 506 continue; 507 } 508 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); 509 switch (numVals / Nc) { 510 case 1: /* P1 Clamped Segment Prism */ 511 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 512 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]); 513 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 514 break; 515 case 3: /* P1 Triangle */ 516 case 4: /* P1 Quadrangle */ 517 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]); 518 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 519 break; 520 case 6: /* P2 Triangle */ 521 case 8: /* P2 Quadrangle */ 522 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]); 523 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 524 break; 525 default: 526 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 527 } 528 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 529 } 530 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 531 switch (numCoords) { 532 case 6: 533 case 12: /* Localized triangle */ 534 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])); 535 break; 536 case 8: 537 case 16: /* Localized quadrilateral */ 538 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 539 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 540 } else { 541 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])); 542 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])); 543 } 544 break; 545 default: 546 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 547 } 548 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 549 } 550 PetscCall(VecRestoreArrayRead(fv, &array)); 551 PetscCall(PetscDrawFlush(draw)); 552 PetscCall(PetscDrawPause(draw)); 553 PetscCall(PetscDrawSave(draw)); 554 } 555 if (Nf > 1) { 556 PetscCall(VecRestoreSubVector(v, fis, &fv)); 557 PetscCall(ISDestroy(&fis)); 558 PetscCall(DMDestroy(&fdm)); 559 } 560 } 561 PetscFunctionReturn(PETSC_SUCCESS); 562 } 563 564 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 565 { 566 DM dm; 567 PetscDraw draw; 568 PetscInt dim; 569 PetscBool isnull; 570 571 PetscFunctionBegin; 572 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 573 PetscCall(PetscDrawIsNull(draw, &isnull)); 574 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 575 576 PetscCall(VecGetDM(v, &dm)); 577 PetscCall(DMGetCoordinateDim(dm, &dim)); 578 switch (dim) { 579 case 1: 580 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 581 break; 582 case 2: 583 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 584 break; 585 default: 586 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 587 } 588 PetscFunctionReturn(PETSC_SUCCESS); 589 } 590 591 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 592 { 593 DM dm; 594 Vec locv; 595 const char *name; 596 PetscSection section; 597 PetscInt pStart, pEnd; 598 PetscInt numFields; 599 PetscViewerVTKFieldType ft; 600 601 PetscFunctionBegin; 602 PetscCall(VecGetDM(v, &dm)); 603 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 604 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 605 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 606 PetscCall(VecCopy(v, locv)); 607 PetscCall(DMGetLocalSection(dm, §ion)); 608 PetscCall(PetscSectionGetNumFields(section, &numFields)); 609 if (!numFields) { 610 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 611 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 612 } else { 613 PetscInt f; 614 615 for (f = 0; f < numFields; f++) { 616 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 617 if (ft == PETSC_VTK_INVALID) continue; 618 PetscCall(PetscObjectReference((PetscObject)locv)); 619 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 620 } 621 PetscCall(VecDestroy(&locv)); 622 } 623 PetscFunctionReturn(PETSC_SUCCESS); 624 } 625 626 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 627 { 628 DM dm; 629 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython; 630 631 PetscFunctionBegin; 632 PetscCall(VecGetDM(v, &dm)); 633 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 639 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 640 if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) { 641 PetscInt i, numFields; 642 PetscObject fe; 643 PetscBool fem = PETSC_FALSE; 644 Vec locv = v; 645 const char *name; 646 PetscInt step; 647 PetscReal time; 648 649 PetscCall(DMGetNumFields(dm, &numFields)); 650 for (i = 0; i < numFields; i++) { 651 PetscCall(DMGetField(dm, i, NULL, &fe)); 652 if (fe->classid == PETSCFE_CLASSID) { 653 fem = PETSC_TRUE; 654 break; 655 } 656 } 657 if (fem) { 658 PetscObject isZero; 659 660 PetscCall(DMGetLocalVector(dm, &locv)); 661 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 662 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 663 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 664 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 665 PetscCall(VecCopy(v, locv)); 666 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 667 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 668 } 669 if (isvtk) { 670 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 671 } else if (ishdf5) { 672 #if defined(PETSC_HAVE_HDF5) 673 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 674 #else 675 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 676 #endif 677 } else if (isdraw) { 678 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 679 } else if (ispython) { 680 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv)); 681 } else if (isglvis) { 682 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 683 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 684 PetscCall(VecView_GLVis(locv, viewer)); 685 } else if (iscgns) { 686 #if defined(PETSC_HAVE_CGNS) 687 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 688 #else 689 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 690 #endif 691 } 692 if (fem) { 693 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 694 PetscCall(DMRestoreLocalVector(dm, &locv)); 695 } 696 } else { 697 PetscBool isseq; 698 699 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 700 if (isseq) PetscCall(VecView_Seq(v, viewer)); 701 else PetscCall(VecView_MPI(v, viewer)); 702 } 703 PetscFunctionReturn(PETSC_SUCCESS); 704 } 705 706 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 707 { 708 DM dm; 709 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython; 710 711 PetscFunctionBegin; 712 PetscCall(VecGetDM(v, &dm)); 713 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 714 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 715 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 716 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 720 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 721 if (isvtk || isdraw || isglvis || iscgns || ispython) { 722 Vec locv; 723 PetscObject isZero; 724 const char *name; 725 726 PetscCall(DMGetLocalVector(dm, &locv)); 727 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 728 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 729 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 730 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 731 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 732 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 733 PetscCall(VecView_Plex_Local(locv, viewer)); 734 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 735 PetscCall(DMRestoreLocalVector(dm, &locv)); 736 } else if (ishdf5) { 737 #if defined(PETSC_HAVE_HDF5) 738 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 739 #else 740 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 741 #endif 742 } else if (isexodusii) { 743 #if defined(PETSC_HAVE_EXODUSII) 744 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 745 #else 746 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 747 #endif 748 } else { 749 PetscBool isseq; 750 751 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 752 if (isseq) PetscCall(VecView_Seq(v, viewer)); 753 else PetscCall(VecView_MPI(v, viewer)); 754 } 755 PetscFunctionReturn(PETSC_SUCCESS); 756 } 757 758 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 759 { 760 DM dm; 761 MPI_Comm comm; 762 PetscViewerFormat format; 763 Vec v; 764 PetscBool isvtk, ishdf5; 765 766 PetscFunctionBegin; 767 PetscCall(VecGetDM(originalv, &dm)); 768 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 769 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 770 PetscCall(PetscViewerGetFormat(viewer, &format)); 771 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 772 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 773 if (format == PETSC_VIEWER_NATIVE) { 774 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 775 /* this need a better fix */ 776 if (dm->useNatural) { 777 if (dm->sfNatural) { 778 const char *vecname; 779 PetscInt n, nroots; 780 781 PetscCall(VecGetLocalSize(originalv, &n)); 782 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 783 if (n == nroots) { 784 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 785 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 786 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 787 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 788 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 789 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 790 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 791 } else v = originalv; 792 } else v = originalv; 793 794 if (ishdf5) { 795 #if defined(PETSC_HAVE_HDF5) 796 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 797 #else 798 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 799 #endif 800 } else if (isvtk) { 801 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 802 } else { 803 PetscBool isseq; 804 805 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 806 if (isseq) PetscCall(VecView_Seq(v, viewer)); 807 else PetscCall(VecView_MPI(v, viewer)); 808 } 809 if (v != originalv) PetscCall(VecDestroy(&v)); 810 PetscFunctionReturn(PETSC_SUCCESS); 811 } 812 813 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 814 { 815 DM dm; 816 PetscBool ishdf5; 817 818 PetscFunctionBegin; 819 PetscCall(VecGetDM(v, &dm)); 820 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 821 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 822 if (ishdf5) { 823 DM dmBC; 824 Vec gv; 825 const char *name; 826 827 PetscCall(DMGetOutputDM(dm, &dmBC)); 828 PetscCall(DMGetGlobalVector(dmBC, &gv)); 829 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 830 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 831 PetscCall(VecLoad_Default(gv, viewer)); 832 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 833 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 834 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 835 } else PetscCall(VecLoad_Default(v, viewer)); 836 PetscFunctionReturn(PETSC_SUCCESS); 837 } 838 839 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 840 { 841 DM dm; 842 PetscBool ishdf5, isexodusii, iscgns; 843 844 PetscFunctionBegin; 845 PetscCall(VecGetDM(v, &dm)); 846 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 847 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 848 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 849 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 850 if (ishdf5) { 851 #if defined(PETSC_HAVE_HDF5) 852 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 853 #else 854 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 855 #endif 856 } else if (isexodusii) { 857 #if defined(PETSC_HAVE_EXODUSII) 858 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 859 #else 860 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 861 #endif 862 } else if (iscgns) { 863 #if defined(PETSC_HAVE_CGNS) 864 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 865 #else 866 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 867 #endif 868 } else PetscCall(VecLoad_Default(v, viewer)); 869 PetscFunctionReturn(PETSC_SUCCESS); 870 } 871 872 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 873 { 874 DM dm; 875 PetscViewerFormat format; 876 PetscBool ishdf5; 877 878 PetscFunctionBegin; 879 PetscCall(VecGetDM(originalv, &dm)); 880 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 881 PetscCall(PetscViewerGetFormat(viewer, &format)); 882 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 883 if (format == PETSC_VIEWER_NATIVE) { 884 if (dm->useNatural) { 885 if (dm->sfNatural) { 886 if (ishdf5) { 887 #if defined(PETSC_HAVE_HDF5) 888 Vec v; 889 const char *vecname; 890 891 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 892 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 893 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 894 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 895 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 896 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 897 PetscCall(VecDestroy(&v)); 898 #else 899 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 900 #endif 901 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 902 } 903 } else PetscCall(VecLoad_Default(originalv, viewer)); 904 } 905 PetscFunctionReturn(PETSC_SUCCESS); 906 } 907 908 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 909 { 910 PetscSection coordSection; 911 Vec coordinates; 912 DMLabel depthLabel, celltypeLabel; 913 const char *name[4]; 914 const PetscScalar *a; 915 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 916 917 PetscFunctionBegin; 918 PetscCall(DMGetDimension(dm, &dim)); 919 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 920 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 921 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 922 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 923 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 924 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 925 PetscCall(VecGetArrayRead(coordinates, &a)); 926 name[0] = "vertex"; 927 name[1] = "edge"; 928 name[dim - 1] = "face"; 929 name[dim] = "cell"; 930 for (c = cStart; c < cEnd; ++c) { 931 PetscInt *closure = NULL; 932 PetscInt closureSize, cl, ct; 933 934 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 935 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 936 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 937 PetscCall(PetscViewerASCIIPushTab(viewer)); 938 for (cl = 0; cl < closureSize * 2; cl += 2) { 939 PetscInt point = closure[cl], depth, dof, off, d, p; 940 941 if ((point < pStart) || (point >= pEnd)) continue; 942 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 943 if (!dof) continue; 944 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 945 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 946 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 947 for (p = 0; p < dof / dim; ++p) { 948 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 949 for (d = 0; d < dim; ++d) { 950 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 951 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 952 } 953 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 954 } 955 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 956 } 957 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 958 PetscCall(PetscViewerASCIIPopTab(viewer)); 959 } 960 PetscCall(VecRestoreArrayRead(coordinates, &a)); 961 PetscFunctionReturn(PETSC_SUCCESS); 962 } 963 964 typedef enum { 965 CS_CARTESIAN, 966 CS_POLAR, 967 CS_CYLINDRICAL, 968 CS_SPHERICAL 969 } CoordSystem; 970 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 971 972 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 973 { 974 PetscInt i; 975 976 PetscFunctionBegin; 977 if (dim > 3) { 978 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 979 } else { 980 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 981 982 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 983 switch (cs) { 984 case CS_CARTESIAN: 985 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 986 break; 987 case CS_POLAR: 988 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 989 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 990 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 991 break; 992 case CS_CYLINDRICAL: 993 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 994 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 995 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 996 trcoords[2] = coords[2]; 997 break; 998 case CS_SPHERICAL: 999 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 1000 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 1001 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 1002 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 1003 break; 1004 } 1005 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 1006 } 1007 PetscFunctionReturn(PETSC_SUCCESS); 1008 } 1009 1010 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 1011 { 1012 DM_Plex *mesh = (DM_Plex *)dm->data; 1013 DM cdm, cdmCell; 1014 PetscSection coordSection, coordSectionCell; 1015 Vec coordinates, coordinatesCell; 1016 PetscViewerFormat format; 1017 1018 PetscFunctionBegin; 1019 PetscCall(PetscViewerGetFormat(viewer, &format)); 1020 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1021 const char *name; 1022 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1023 PetscInt pStart, pEnd, p, numLabels, l; 1024 PetscMPIInt rank, size; 1025 1026 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1027 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1028 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1029 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1030 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1031 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1032 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1033 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1034 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1035 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1036 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1037 PetscCall(DMGetDimension(dm, &dim)); 1038 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1039 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1040 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1041 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1042 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1043 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1044 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1045 for (p = pStart; p < pEnd; ++p) { 1046 PetscInt dof, off, s; 1047 1048 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1049 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1050 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1051 } 1052 PetscCall(PetscViewerFlush(viewer)); 1053 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1054 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1055 for (p = pStart; p < pEnd; ++p) { 1056 PetscInt dof, off, c; 1057 1058 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1059 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1060 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])); 1061 } 1062 PetscCall(PetscViewerFlush(viewer)); 1063 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1064 if (coordSection && coordinates) { 1065 CoordSystem cs = CS_CARTESIAN; 1066 const PetscScalar *array, *arrayCell = NULL; 1067 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1068 PetscMPIInt rank; 1069 const char *name; 1070 1071 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1072 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1073 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1074 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1075 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1076 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1077 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1078 pStart = PetscMin(pvStart, pcStart); 1079 pEnd = PetscMax(pvEnd, pcEnd); 1080 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1081 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1082 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1083 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1084 1085 PetscCall(VecGetArrayRead(coordinates, &array)); 1086 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1087 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1088 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1089 for (p = pStart; p < pEnd; ++p) { 1090 PetscInt dof, off; 1091 1092 if (p >= pvStart && p < pvEnd) { 1093 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1094 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1095 if (dof) { 1096 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1097 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1098 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1099 } 1100 } 1101 if (cdmCell && p >= pcStart && p < pcEnd) { 1102 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1103 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1104 if (dof) { 1105 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1106 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1107 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1108 } 1109 } 1110 } 1111 PetscCall(PetscViewerFlush(viewer)); 1112 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1113 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1114 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1115 } 1116 PetscCall(DMGetNumLabels(dm, &numLabels)); 1117 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1118 for (l = 0; l < numLabels; ++l) { 1119 DMLabel label; 1120 PetscBool isdepth; 1121 const char *name; 1122 1123 PetscCall(DMGetLabelName(dm, l, &name)); 1124 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1125 if (isdepth) continue; 1126 PetscCall(DMGetLabel(dm, name, &label)); 1127 PetscCall(DMLabelView(label, viewer)); 1128 } 1129 if (size > 1) { 1130 PetscSF sf; 1131 1132 PetscCall(DMGetPointSF(dm, &sf)); 1133 PetscCall(PetscSFView(sf, viewer)); 1134 } 1135 if (mesh->periodic.face_sfs) 1136 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1137 PetscCall(PetscViewerFlush(viewer)); 1138 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1139 const char *name, *color; 1140 const char *defcolors[3] = {"gray", "orange", "green"}; 1141 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1142 char lname[PETSC_MAX_PATH_LEN]; 1143 PetscReal scale = 2.0; 1144 PetscReal tikzscale = 1.0; 1145 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1146 double tcoords[3]; 1147 PetscScalar *coords; 1148 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; 1149 PetscMPIInt rank, size; 1150 char **names, **colors, **lcolors; 1151 PetscBool flg, lflg; 1152 PetscBT wp = NULL; 1153 PetscInt pEnd, pStart; 1154 1155 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1156 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1157 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1158 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1159 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1160 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1161 PetscCall(DMGetDimension(dm, &dim)); 1162 PetscCall(DMPlexGetDepth(dm, &depth)); 1163 PetscCall(DMGetNumLabels(dm, &numLabels)); 1164 numLabels = PetscMax(numLabels, 10); 1165 numColors = 10; 1166 numLColors = 10; 1167 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1168 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1169 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1170 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1171 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1172 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1173 n = 4; 1174 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1175 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1176 n = 4; 1177 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1178 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1179 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1180 if (!useLabels) numLabels = 0; 1181 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1182 if (!useColors) { 1183 numColors = 3; 1184 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1185 } 1186 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1187 if (!useColors) { 1188 numLColors = 4; 1189 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1190 } 1191 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1192 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1193 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1194 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1195 if (depth < dim) plotEdges = PETSC_FALSE; 1196 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1197 1198 /* filter points with labelvalue != labeldefaultvalue */ 1199 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1200 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1201 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1202 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1203 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1204 if (lflg) { 1205 DMLabel lbl; 1206 1207 PetscCall(DMGetLabel(dm, lname, &lbl)); 1208 if (lbl) { 1209 PetscInt val, defval; 1210 1211 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1212 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1213 for (c = pStart; c < pEnd; c++) { 1214 PetscInt *closure = NULL; 1215 PetscInt closureSize; 1216 1217 PetscCall(DMLabelGetValue(lbl, c, &val)); 1218 if (val == defval) continue; 1219 1220 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1221 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1222 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1223 } 1224 } 1225 } 1226 1227 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1228 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1229 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1230 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1231 \\documentclass[tikz]{standalone}\n\n\ 1232 \\usepackage{pgflibraryshapes}\n\ 1233 \\usetikzlibrary{backgrounds}\n\ 1234 \\usetikzlibrary{arrows}\n\ 1235 \\begin{document}\n")); 1236 if (size > 1) { 1237 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1238 for (p = 0; p < size; ++p) { 1239 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1240 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1241 } 1242 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1243 } 1244 if (drawHasse) { 1245 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1246 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1249 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1258 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1263 } 1264 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1265 1266 /* Plot vertices */ 1267 PetscCall(VecGetArray(coordinates, &coords)); 1268 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1269 for (v = vStart; v < vEnd; ++v) { 1270 PetscInt off, dof, d; 1271 PetscBool isLabeled = PETSC_FALSE; 1272 1273 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1274 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1275 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1276 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1277 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1278 for (d = 0; d < dof; ++d) { 1279 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1280 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1281 } 1282 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1283 if (dim == 3) { 1284 PetscReal tmp = tcoords[1]; 1285 tcoords[1] = tcoords[2]; 1286 tcoords[2] = -tmp; 1287 } 1288 for (d = 0; d < dof; ++d) { 1289 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1290 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1291 } 1292 if (drawHasse) color = colors[0 % numColors]; 1293 else color = colors[rank % numColors]; 1294 for (l = 0; l < numLabels; ++l) { 1295 PetscInt val; 1296 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1297 if (val >= 0) { 1298 color = lcolors[l % numLColors]; 1299 isLabeled = PETSC_TRUE; 1300 break; 1301 } 1302 } 1303 if (drawNumbers[0]) { 1304 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1305 } else if (drawColors[0]) { 1306 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1307 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1308 } 1309 PetscCall(VecRestoreArray(coordinates, &coords)); 1310 PetscCall(PetscViewerFlush(viewer)); 1311 /* Plot edges */ 1312 if (plotEdges) { 1313 PetscCall(VecGetArray(coordinates, &coords)); 1314 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1315 for (e = eStart; e < eEnd; ++e) { 1316 const PetscInt *cone; 1317 PetscInt coneSize, offA, offB, dof, d; 1318 1319 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1320 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1321 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1322 PetscCall(DMPlexGetCone(dm, e, &cone)); 1323 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1324 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1325 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1326 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1327 for (d = 0; d < dof; ++d) { 1328 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1329 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1330 } 1331 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1332 if (dim == 3) { 1333 PetscReal tmp = tcoords[1]; 1334 tcoords[1] = tcoords[2]; 1335 tcoords[2] = -tmp; 1336 } 1337 for (d = 0; d < dof; ++d) { 1338 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1339 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1340 } 1341 if (drawHasse) color = colors[1 % numColors]; 1342 else color = colors[rank % numColors]; 1343 for (l = 0; l < numLabels; ++l) { 1344 PetscInt val; 1345 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1346 if (val >= 0) { 1347 color = lcolors[l % numLColors]; 1348 break; 1349 } 1350 } 1351 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1352 } 1353 PetscCall(VecRestoreArray(coordinates, &coords)); 1354 PetscCall(PetscViewerFlush(viewer)); 1355 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1356 } 1357 /* Plot cells */ 1358 if (dim == 3 || !drawNumbers[1]) { 1359 for (e = eStart; e < eEnd; ++e) { 1360 const PetscInt *cone; 1361 1362 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1363 color = colors[rank % numColors]; 1364 for (l = 0; l < numLabels; ++l) { 1365 PetscInt val; 1366 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1367 if (val >= 0) { 1368 color = lcolors[l % numLColors]; 1369 break; 1370 } 1371 } 1372 PetscCall(DMPlexGetCone(dm, e, &cone)); 1373 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1374 } 1375 } else { 1376 DMPolytopeType ct; 1377 1378 /* Drawing a 2D polygon */ 1379 for (c = cStart; c < cEnd; ++c) { 1380 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1381 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1382 if (DMPolytopeTypeIsHybrid(ct)) { 1383 const PetscInt *cone; 1384 PetscInt coneSize, e; 1385 1386 PetscCall(DMPlexGetCone(dm, c, &cone)); 1387 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1388 for (e = 0; e < coneSize; ++e) { 1389 const PetscInt *econe; 1390 1391 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1392 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)); 1393 } 1394 } else { 1395 PetscInt *closure = NULL; 1396 PetscInt closureSize, Nv = 0, v; 1397 1398 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1399 for (p = 0; p < closureSize * 2; p += 2) { 1400 const PetscInt point = closure[p]; 1401 1402 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1403 } 1404 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1405 for (v = 0; v <= Nv; ++v) { 1406 const PetscInt vertex = closure[v % Nv]; 1407 1408 if (v > 0) { 1409 if (plotEdges) { 1410 const PetscInt *edge; 1411 PetscInt endpoints[2], ne; 1412 1413 endpoints[0] = closure[v - 1]; 1414 endpoints[1] = vertex; 1415 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1416 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1417 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1418 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1419 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1420 } 1421 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1422 } 1423 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1424 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1425 } 1426 } 1427 } 1428 for (c = cStart; c < cEnd; ++c) { 1429 double ccoords[3] = {0.0, 0.0, 0.0}; 1430 PetscBool isLabeled = PETSC_FALSE; 1431 PetscScalar *cellCoords = NULL; 1432 const PetscScalar *array; 1433 PetscInt numCoords, cdim, d; 1434 PetscBool isDG; 1435 1436 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1437 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1438 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1439 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1440 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1441 for (p = 0; p < numCoords / cdim; ++p) { 1442 for (d = 0; d < cdim; ++d) { 1443 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1444 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1445 } 1446 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1447 if (cdim == 3) { 1448 PetscReal tmp = tcoords[1]; 1449 tcoords[1] = tcoords[2]; 1450 tcoords[2] = -tmp; 1451 } 1452 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1453 } 1454 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1455 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1456 for (d = 0; d < cdim; ++d) { 1457 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1458 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1459 } 1460 if (drawHasse) color = colors[depth % numColors]; 1461 else color = colors[rank % numColors]; 1462 for (l = 0; l < numLabels; ++l) { 1463 PetscInt val; 1464 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1465 if (val >= 0) { 1466 color = lcolors[l % numLColors]; 1467 isLabeled = PETSC_TRUE; 1468 break; 1469 } 1470 } 1471 if (drawNumbers[dim]) { 1472 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1473 } else if (drawColors[dim]) { 1474 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1475 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1476 } 1477 if (drawHasse) { 1478 int height = 0; 1479 1480 color = colors[depth % numColors]; 1481 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1482 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1483 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1484 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1485 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1486 1487 if (depth > 2) { 1488 color = colors[1 % numColors]; 1489 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1490 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1491 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1492 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1493 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1494 } 1495 1496 color = colors[1 % numColors]; 1497 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1498 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1499 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1500 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1502 1503 color = colors[0 % numColors]; 1504 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1505 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1506 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1507 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1509 1510 for (p = pStart; p < pEnd; ++p) { 1511 const PetscInt *cone; 1512 PetscInt coneSize, cp; 1513 1514 PetscCall(DMPlexGetCone(dm, p, &cone)); 1515 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1516 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1517 } 1518 } 1519 PetscCall(PetscViewerFlush(viewer)); 1520 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1521 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1522 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1523 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1524 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1525 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1526 PetscCall(PetscFree3(names, colors, lcolors)); 1527 PetscCall(PetscBTDestroy(&wp)); 1528 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1529 Vec cown, acown; 1530 VecScatter sct; 1531 ISLocalToGlobalMapping g2l; 1532 IS gid, acis; 1533 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1534 MPI_Group ggroup, ngroup; 1535 PetscScalar *array, nid; 1536 const PetscInt *idxs; 1537 PetscInt *idxs2, *start, *adjacency, *work; 1538 PetscInt64 lm[3], gm[3]; 1539 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1540 PetscMPIInt d1, d2, rank; 1541 1542 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1543 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1544 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1545 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1546 #endif 1547 if (ncomm != MPI_COMM_NULL) { 1548 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1549 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1550 d1 = 0; 1551 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1552 nid = d2; 1553 PetscCallMPI(MPI_Group_free(&ggroup)); 1554 PetscCallMPI(MPI_Group_free(&ngroup)); 1555 PetscCallMPI(MPI_Comm_free(&ncomm)); 1556 } else nid = 0.0; 1557 1558 /* Get connectivity */ 1559 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1560 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1561 1562 /* filter overlapped local cells */ 1563 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1564 PetscCall(ISGetIndices(gid, &idxs)); 1565 PetscCall(ISGetLocalSize(gid, &cum)); 1566 PetscCall(PetscMalloc1(cum, &idxs2)); 1567 for (c = cStart, cum = 0; c < cEnd; c++) { 1568 if (idxs[c - cStart] < 0) continue; 1569 idxs2[cum++] = idxs[c - cStart]; 1570 } 1571 PetscCall(ISRestoreIndices(gid, &idxs)); 1572 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1573 PetscCall(ISDestroy(&gid)); 1574 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1575 1576 /* support for node-aware cell locality */ 1577 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1578 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1579 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1580 PetscCall(VecGetArray(cown, &array)); 1581 for (c = 0; c < numVertices; c++) array[c] = nid; 1582 PetscCall(VecRestoreArray(cown, &array)); 1583 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1584 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1585 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1586 PetscCall(ISDestroy(&acis)); 1587 PetscCall(VecScatterDestroy(&sct)); 1588 PetscCall(VecDestroy(&cown)); 1589 1590 /* compute edgeCut */ 1591 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1592 PetscCall(PetscMalloc1(cum, &work)); 1593 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1594 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1595 PetscCall(ISDestroy(&gid)); 1596 PetscCall(VecGetArray(acown, &array)); 1597 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1598 PetscInt totl; 1599 1600 totl = start[c + 1] - start[c]; 1601 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1602 for (i = 0; i < totl; i++) { 1603 if (work[i] < 0) { 1604 ect += 1; 1605 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1606 } 1607 } 1608 } 1609 PetscCall(PetscFree(work)); 1610 PetscCall(VecRestoreArray(acown, &array)); 1611 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1612 lm[1] = -numVertices; 1613 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1614 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1615 lm[0] = ect; /* edgeCut */ 1616 lm[1] = ectn; /* node-aware edgeCut */ 1617 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1618 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1619 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1620 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1621 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1622 #else 1623 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1624 #endif 1625 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1626 PetscCall(PetscFree(start)); 1627 PetscCall(PetscFree(adjacency)); 1628 PetscCall(VecDestroy(&acown)); 1629 } else { 1630 const char *name; 1631 PetscInt *sizes, *hybsizes, *ghostsizes; 1632 PetscInt locDepth, depth, cellHeight, dim, d; 1633 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1634 PetscInt numLabels, l, maxSize = 17; 1635 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1636 MPI_Comm comm; 1637 PetscMPIInt size, rank; 1638 1639 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1640 PetscCallMPI(MPI_Comm_size(comm, &size)); 1641 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1642 PetscCall(DMGetDimension(dm, &dim)); 1643 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1644 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1645 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1646 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1647 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1648 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1649 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1650 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1651 gcNum = gcEnd - gcStart; 1652 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1653 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1654 for (d = 0; d <= depth; d++) { 1655 PetscInt Nc[2] = {0, 0}, ict; 1656 1657 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1658 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1659 ict = ct0; 1660 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1661 ct0 = (DMPolytopeType)ict; 1662 for (p = pStart; p < pEnd; ++p) { 1663 DMPolytopeType ct; 1664 1665 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1666 if (ct == ct0) ++Nc[0]; 1667 else ++Nc[1]; 1668 } 1669 if (size < maxSize) { 1670 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1671 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1672 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1673 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1674 for (p = 0; p < size; ++p) { 1675 if (rank == 0) { 1676 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1677 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1678 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1679 } 1680 } 1681 } else { 1682 PetscInt locMinMax[2]; 1683 1684 locMinMax[0] = Nc[0] + Nc[1]; 1685 locMinMax[1] = Nc[0] + Nc[1]; 1686 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1687 locMinMax[0] = Nc[1]; 1688 locMinMax[1] = Nc[1]; 1689 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1690 if (d == depth) { 1691 locMinMax[0] = gcNum; 1692 locMinMax[1] = gcNum; 1693 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1694 } 1695 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1696 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1697 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1698 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1699 } 1700 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1701 } 1702 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1703 { 1704 const PetscReal *maxCell; 1705 const PetscReal *L; 1706 PetscBool localized; 1707 1708 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1709 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1710 if (L || localized) { 1711 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1712 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1713 if (L) { 1714 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1715 for (d = 0; d < dim; ++d) { 1716 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1717 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1718 } 1719 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1720 } 1721 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1722 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1723 } 1724 } 1725 PetscCall(DMGetNumLabels(dm, &numLabels)); 1726 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1727 for (l = 0; l < numLabels; ++l) { 1728 DMLabel label; 1729 const char *name; 1730 PetscInt *values; 1731 PetscInt numValues, v; 1732 1733 PetscCall(DMGetLabelName(dm, l, &name)); 1734 PetscCall(DMGetLabel(dm, name, &label)); 1735 PetscCall(DMLabelGetNumValues(label, &numValues)); 1736 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1737 1738 { // Extract array of DMLabel values so it can be sorted 1739 IS is_values; 1740 const PetscInt *is_values_local = NULL; 1741 1742 PetscCall(DMLabelGetValueIS(label, &is_values)); 1743 PetscCall(ISGetIndices(is_values, &is_values_local)); 1744 PetscCall(PetscMalloc1(numValues, &values)); 1745 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1746 PetscCall(PetscSortInt(numValues, values)); 1747 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1748 PetscCall(ISDestroy(&is_values)); 1749 } 1750 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1751 for (v = 0; v < numValues; ++v) { 1752 PetscInt size; 1753 1754 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1755 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1756 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1757 } 1758 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1759 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1760 PetscCall(PetscFree(values)); 1761 } 1762 { 1763 char **labelNames; 1764 PetscInt Nl = numLabels; 1765 PetscBool flg; 1766 1767 PetscCall(PetscMalloc1(Nl, &labelNames)); 1768 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1769 for (l = 0; l < Nl; ++l) { 1770 DMLabel label; 1771 1772 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1773 if (flg) { 1774 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1775 PetscCall(DMLabelView(label, viewer)); 1776 } 1777 PetscCall(PetscFree(labelNames[l])); 1778 } 1779 PetscCall(PetscFree(labelNames)); 1780 } 1781 /* If no fields are specified, people do not want to see adjacency */ 1782 if (dm->Nf) { 1783 PetscInt f; 1784 1785 for (f = 0; f < dm->Nf; ++f) { 1786 const char *name; 1787 1788 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1789 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1790 PetscCall(PetscViewerASCIIPushTab(viewer)); 1791 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1792 if (dm->fields[f].adjacency[0]) { 1793 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1794 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1795 } else { 1796 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1797 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1798 } 1799 PetscCall(PetscViewerASCIIPopTab(viewer)); 1800 } 1801 } 1802 PetscCall(DMGetCoarseDM(dm, &cdm)); 1803 if (cdm) { 1804 PetscCall(PetscViewerASCIIPushTab(viewer)); 1805 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1806 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1807 PetscCall(PetscViewerASCIIPopTab(viewer)); 1808 } 1809 } 1810 PetscFunctionReturn(PETSC_SUCCESS); 1811 } 1812 1813 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1814 { 1815 DMPolytopeType ct; 1816 PetscMPIInt rank; 1817 PetscInt cdim; 1818 1819 PetscFunctionBegin; 1820 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1821 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1822 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1823 switch (ct) { 1824 case DM_POLYTOPE_SEGMENT: 1825 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1826 switch (cdim) { 1827 case 1: { 1828 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1829 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1830 1831 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1832 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1833 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1834 } break; 1835 case 2: { 1836 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1837 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1838 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1839 1840 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1841 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1842 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1843 } break; 1844 default: 1845 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1846 } 1847 break; 1848 case DM_POLYTOPE_TRIANGLE: 1849 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1850 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1851 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1852 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1853 break; 1854 case DM_POLYTOPE_QUADRILATERAL: 1855 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1856 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1857 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1858 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1859 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1860 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1861 break; 1862 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1863 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1864 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1865 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1866 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1867 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1868 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1869 break; 1870 case DM_POLYTOPE_FV_GHOST: 1871 break; 1872 default: 1873 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1874 } 1875 PetscFunctionReturn(PETSC_SUCCESS); 1876 } 1877 1878 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1879 { 1880 PetscReal centroid[2] = {0., 0.}; 1881 PetscMPIInt rank; 1882 PetscMPIInt fillColor; 1883 1884 PetscFunctionBegin; 1885 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1886 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1887 for (PetscInt v = 0; v < Nv; ++v) { 1888 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1889 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1890 } 1891 for (PetscInt e = 0; e < Nv; ++e) { 1892 refCoords[0] = refVertices[e * 2 + 0]; 1893 refCoords[1] = refVertices[e * 2 + 1]; 1894 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1895 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1896 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1897 } 1898 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1899 for (PetscInt d = 0; d < edgeDiv; ++d) { 1900 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)); 1901 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1902 } 1903 } 1904 PetscFunctionReturn(PETSC_SUCCESS); 1905 } 1906 1907 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1908 { 1909 DMPolytopeType ct; 1910 1911 PetscFunctionBegin; 1912 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1913 switch (ct) { 1914 case DM_POLYTOPE_TRIANGLE: { 1915 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1916 1917 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1918 } break; 1919 case DM_POLYTOPE_QUADRILATERAL: { 1920 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1921 1922 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1923 } break; 1924 default: 1925 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1926 } 1927 PetscFunctionReturn(PETSC_SUCCESS); 1928 } 1929 1930 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1931 { 1932 PetscDraw draw; 1933 DM cdm; 1934 PetscSection coordSection; 1935 Vec coordinates; 1936 PetscReal xyl[3], xyr[3]; 1937 PetscReal *refCoords, *edgeCoords; 1938 PetscBool isnull, drawAffine; 1939 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1940 1941 PetscFunctionBegin; 1942 PetscCall(DMGetCoordinateDim(dm, &dim)); 1943 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1944 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1945 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1946 edgeDiv = cDegree + 1; 1947 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1948 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1949 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1950 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1951 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1952 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1953 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1954 1955 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1956 PetscCall(PetscDrawIsNull(draw, &isnull)); 1957 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1958 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1959 1960 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1961 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1962 PetscCall(PetscDrawClear(draw)); 1963 1964 for (c = cStart; c < cEnd; ++c) { 1965 PetscScalar *coords = NULL; 1966 const PetscScalar *coords_arr; 1967 PetscInt numCoords; 1968 PetscBool isDG; 1969 1970 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1971 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1972 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1973 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1974 } 1975 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1976 PetscCall(PetscDrawFlush(draw)); 1977 PetscCall(PetscDrawPause(draw)); 1978 PetscCall(PetscDrawSave(draw)); 1979 PetscFunctionReturn(PETSC_SUCCESS); 1980 } 1981 1982 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1983 { 1984 DM odm = dm, rdm = dm, cdm; 1985 PetscFE fe; 1986 PetscSpace sp; 1987 PetscClassId id; 1988 PetscInt degree; 1989 PetscBool hoView = PETSC_TRUE; 1990 1991 PetscFunctionBegin; 1992 PetscObjectOptionsBegin((PetscObject)dm); 1993 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1994 PetscOptionsEnd(); 1995 PetscCall(PetscObjectReference((PetscObject)dm)); 1996 *hdm = dm; 1997 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1998 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1999 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 2000 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 2001 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 2002 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 2003 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 2004 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 2005 DM cdm, rcdm; 2006 Mat In; 2007 Vec cl, rcl; 2008 2009 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 2010 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 2011 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 2012 PetscCall(DMGetCoordinateDM(odm, &cdm)); 2013 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 2014 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 2015 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 2016 PetscCall(DMSetCoarseDM(rcdm, cdm)); 2017 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 2018 PetscCall(MatMult(In, cl, rcl)); 2019 PetscCall(MatDestroy(&In)); 2020 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 2021 PetscCall(DMDestroy(&odm)); 2022 odm = rdm; 2023 } 2024 *hdm = rdm; 2025 PetscFunctionReturn(PETSC_SUCCESS); 2026 } 2027 2028 #if defined(PETSC_HAVE_EXODUSII) 2029 #include <exodusII.h> 2030 #include <petscviewerexodusii.h> 2031 #endif 2032 2033 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 2034 { 2035 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 2036 char name[PETSC_MAX_PATH_LEN]; 2037 2038 PetscFunctionBegin; 2039 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2040 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2041 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 2042 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2043 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2044 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2045 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 2046 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 2047 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 2048 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2049 if (iascii) { 2050 PetscViewerFormat format; 2051 PetscCall(PetscViewerGetFormat(viewer, &format)); 2052 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 2053 else PetscCall(DMPlexView_Ascii(dm, viewer)); 2054 } else if (ishdf5) { 2055 #if defined(PETSC_HAVE_HDF5) 2056 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 2057 #else 2058 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2059 #endif 2060 } else if (isvtk) { 2061 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2062 } else if (isdraw) { 2063 DM hdm; 2064 2065 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2066 PetscCall(DMPlexView_Draw(hdm, viewer)); 2067 PetscCall(DMDestroy(&hdm)); 2068 } else if (isglvis) { 2069 PetscCall(DMPlexView_GLVis(dm, viewer)); 2070 #if defined(PETSC_HAVE_EXODUSII) 2071 } else if (isexodus) { 2072 /* 2073 exodusII requires that all sets be part of exactly one cell set. 2074 If the dm does not have a "Cell Sets" label defined, we create one 2075 with ID 1, containing all cells. 2076 Note that if the Cell Sets label is defined but does not cover all cells, 2077 we may still have a problem. This should probably be checked here or in the viewer; 2078 */ 2079 PetscInt numCS; 2080 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2081 if (!numCS) { 2082 PetscInt cStart, cEnd, c; 2083 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2084 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2085 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2086 } 2087 PetscCall(DMView_PlexExodusII(dm, viewer)); 2088 #endif 2089 #if defined(PETSC_HAVE_CGNS) 2090 } else if (iscgns) { 2091 PetscCall(DMView_PlexCGNS(dm, viewer)); 2092 #endif 2093 } else if (ispython) { 2094 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2095 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2096 /* Optionally view the partition */ 2097 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2098 if (flg) { 2099 Vec ranks; 2100 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2101 PetscCall(VecView(ranks, viewer)); 2102 PetscCall(VecDestroy(&ranks)); 2103 } 2104 /* Optionally view a label */ 2105 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2106 if (flg) { 2107 DMLabel label; 2108 Vec val; 2109 2110 PetscCall(DMGetLabel(dm, name, &label)); 2111 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2112 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2113 PetscCall(VecView(val, viewer)); 2114 PetscCall(VecDestroy(&val)); 2115 } 2116 PetscFunctionReturn(PETSC_SUCCESS); 2117 } 2118 2119 /*@ 2120 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2121 2122 Collective 2123 2124 Input Parameters: 2125 + dm - The `DM` whose topology is to be saved 2126 - viewer - The `PetscViewer` to save it in 2127 2128 Level: advanced 2129 2130 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2131 @*/ 2132 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2133 { 2134 PetscBool ishdf5; 2135 2136 PetscFunctionBegin; 2137 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2138 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2139 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2140 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2141 if (ishdf5) { 2142 #if defined(PETSC_HAVE_HDF5) 2143 PetscViewerFormat format; 2144 PetscCall(PetscViewerGetFormat(viewer, &format)); 2145 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2146 IS globalPointNumbering; 2147 2148 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2149 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2150 PetscCall(ISDestroy(&globalPointNumbering)); 2151 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2152 #else 2153 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2154 #endif 2155 } 2156 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2157 PetscFunctionReturn(PETSC_SUCCESS); 2158 } 2159 2160 /*@ 2161 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2162 2163 Collective 2164 2165 Input Parameters: 2166 + dm - The `DM` whose coordinates are to be saved 2167 - viewer - The `PetscViewer` for saving 2168 2169 Level: advanced 2170 2171 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2172 @*/ 2173 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2174 { 2175 PetscBool ishdf5; 2176 2177 PetscFunctionBegin; 2178 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2179 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2180 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2181 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2182 if (ishdf5) { 2183 #if defined(PETSC_HAVE_HDF5) 2184 PetscViewerFormat format; 2185 PetscCall(PetscViewerGetFormat(viewer, &format)); 2186 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2187 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2188 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2189 #else 2190 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2191 #endif 2192 } 2193 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2194 PetscFunctionReturn(PETSC_SUCCESS); 2195 } 2196 2197 /*@ 2198 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2199 2200 Collective 2201 2202 Input Parameters: 2203 + dm - The `DM` whose labels are to be saved 2204 - viewer - The `PetscViewer` for saving 2205 2206 Level: advanced 2207 2208 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2209 @*/ 2210 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2211 { 2212 PetscBool ishdf5; 2213 2214 PetscFunctionBegin; 2215 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2216 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2217 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2218 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2219 if (ishdf5) { 2220 #if defined(PETSC_HAVE_HDF5) 2221 IS globalPointNumbering; 2222 PetscViewerFormat format; 2223 2224 PetscCall(PetscViewerGetFormat(viewer, &format)); 2225 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2226 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2227 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2228 PetscCall(ISDestroy(&globalPointNumbering)); 2229 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2230 #else 2231 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2232 #endif 2233 } 2234 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2235 PetscFunctionReturn(PETSC_SUCCESS); 2236 } 2237 2238 /*@ 2239 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2240 2241 Collective 2242 2243 Input Parameters: 2244 + dm - The `DM` that contains the topology on which the section to be saved is defined 2245 . viewer - The `PetscViewer` for saving 2246 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2247 2248 Level: advanced 2249 2250 Notes: 2251 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. 2252 2253 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2254 2255 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2256 @*/ 2257 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2258 { 2259 PetscBool ishdf5; 2260 2261 PetscFunctionBegin; 2262 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2263 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2264 if (!sectiondm) sectiondm = dm; 2265 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2266 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2267 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2268 if (ishdf5) { 2269 #if defined(PETSC_HAVE_HDF5) 2270 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2271 #else 2272 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2273 #endif 2274 } 2275 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2276 PetscFunctionReturn(PETSC_SUCCESS); 2277 } 2278 2279 /*@ 2280 DMPlexGlobalVectorView - Saves a global vector 2281 2282 Collective 2283 2284 Input Parameters: 2285 + dm - The `DM` that represents the topology 2286 . viewer - The `PetscViewer` to save data with 2287 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2288 - vec - The global vector to be saved 2289 2290 Level: advanced 2291 2292 Notes: 2293 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. 2294 2295 Calling sequence: 2296 .vb 2297 DMCreate(PETSC_COMM_WORLD, &dm); 2298 DMSetType(dm, DMPLEX); 2299 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2300 DMClone(dm, §iondm); 2301 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2302 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2303 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2304 PetscSectionSetChart(section, pStart, pEnd); 2305 PetscSectionSetUp(section); 2306 DMSetLocalSection(sectiondm, section); 2307 PetscSectionDestroy(§ion); 2308 DMGetGlobalVector(sectiondm, &vec); 2309 PetscObjectSetName((PetscObject)vec, "vec_name"); 2310 DMPlexTopologyView(dm, viewer); 2311 DMPlexSectionView(dm, viewer, sectiondm); 2312 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2313 DMRestoreGlobalVector(sectiondm, &vec); 2314 DMDestroy(§iondm); 2315 DMDestroy(&dm); 2316 .ve 2317 2318 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2319 @*/ 2320 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2321 { 2322 PetscBool ishdf5; 2323 2324 PetscFunctionBegin; 2325 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2326 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2327 if (!sectiondm) sectiondm = dm; 2328 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2329 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2330 /* Check consistency */ 2331 { 2332 PetscSection section; 2333 PetscBool includesConstraints; 2334 PetscInt m, m1; 2335 2336 PetscCall(VecGetLocalSize(vec, &m1)); 2337 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2338 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2339 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2340 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2341 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2342 } 2343 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2344 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2345 if (ishdf5) { 2346 #if defined(PETSC_HAVE_HDF5) 2347 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2348 #else 2349 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2350 #endif 2351 } 2352 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2353 PetscFunctionReturn(PETSC_SUCCESS); 2354 } 2355 2356 /*@ 2357 DMPlexLocalVectorView - Saves a local vector 2358 2359 Collective 2360 2361 Input Parameters: 2362 + dm - The `DM` that represents the topology 2363 . viewer - The `PetscViewer` to save data with 2364 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2365 - vec - The local vector to be saved 2366 2367 Level: advanced 2368 2369 Note: 2370 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. 2371 2372 Calling sequence: 2373 .vb 2374 DMCreate(PETSC_COMM_WORLD, &dm); 2375 DMSetType(dm, DMPLEX); 2376 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2377 DMClone(dm, §iondm); 2378 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2379 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2380 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2381 PetscSectionSetChart(section, pStart, pEnd); 2382 PetscSectionSetUp(section); 2383 DMSetLocalSection(sectiondm, section); 2384 DMGetLocalVector(sectiondm, &vec); 2385 PetscObjectSetName((PetscObject)vec, "vec_name"); 2386 DMPlexTopologyView(dm, viewer); 2387 DMPlexSectionView(dm, viewer, sectiondm); 2388 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2389 DMRestoreLocalVector(sectiondm, &vec); 2390 DMDestroy(§iondm); 2391 DMDestroy(&dm); 2392 .ve 2393 2394 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2395 @*/ 2396 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2397 { 2398 PetscBool ishdf5; 2399 2400 PetscFunctionBegin; 2401 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2402 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2403 if (!sectiondm) sectiondm = dm; 2404 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2405 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2406 /* Check consistency */ 2407 { 2408 PetscSection section; 2409 PetscBool includesConstraints; 2410 PetscInt m, m1; 2411 2412 PetscCall(VecGetLocalSize(vec, &m1)); 2413 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2414 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2415 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2416 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2417 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2418 } 2419 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2420 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2421 if (ishdf5) { 2422 #if defined(PETSC_HAVE_HDF5) 2423 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2424 #else 2425 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2426 #endif 2427 } 2428 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2429 PetscFunctionReturn(PETSC_SUCCESS); 2430 } 2431 2432 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2433 { 2434 PetscBool ishdf5; 2435 2436 PetscFunctionBegin; 2437 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2438 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2439 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2440 if (ishdf5) { 2441 #if defined(PETSC_HAVE_HDF5) 2442 PetscViewerFormat format; 2443 PetscCall(PetscViewerGetFormat(viewer, &format)); 2444 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2445 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2446 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2447 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2448 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2449 PetscFunctionReturn(PETSC_SUCCESS); 2450 #else 2451 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2452 #endif 2453 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2454 } 2455 2456 /*@ 2457 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2458 2459 Collective 2460 2461 Input Parameters: 2462 + dm - The `DM` into which the topology is loaded 2463 - viewer - The `PetscViewer` for the saved topology 2464 2465 Output Parameter: 2466 . 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; 2467 `NULL` if unneeded 2468 2469 Level: advanced 2470 2471 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2472 `PetscViewer`, `PetscSF` 2473 @*/ 2474 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2475 { 2476 PetscBool ishdf5; 2477 2478 PetscFunctionBegin; 2479 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2480 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2481 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2482 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2483 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2484 if (ishdf5) { 2485 #if defined(PETSC_HAVE_HDF5) 2486 PetscViewerFormat format; 2487 PetscCall(PetscViewerGetFormat(viewer, &format)); 2488 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2489 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2490 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2491 #else 2492 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2493 #endif 2494 } 2495 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2496 PetscFunctionReturn(PETSC_SUCCESS); 2497 } 2498 2499 /*@ 2500 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2501 2502 Collective 2503 2504 Input Parameters: 2505 + dm - The `DM` into which the coordinates are loaded 2506 . viewer - The `PetscViewer` for the saved coordinates 2507 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2508 2509 Level: advanced 2510 2511 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2512 `PetscSF`, `PetscViewer` 2513 @*/ 2514 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2515 { 2516 PetscBool ishdf5; 2517 2518 PetscFunctionBegin; 2519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2520 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2521 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2522 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2523 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2524 if (ishdf5) { 2525 #if defined(PETSC_HAVE_HDF5) 2526 PetscViewerFormat format; 2527 PetscCall(PetscViewerGetFormat(viewer, &format)); 2528 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2529 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2530 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2531 #else 2532 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2533 #endif 2534 } 2535 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2536 PetscFunctionReturn(PETSC_SUCCESS); 2537 } 2538 2539 /*@ 2540 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2541 2542 Collective 2543 2544 Input Parameters: 2545 + dm - The `DM` into which the labels are loaded 2546 . viewer - The `PetscViewer` for the saved labels 2547 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2548 2549 Level: advanced 2550 2551 Note: 2552 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2553 2554 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2555 `PetscSF`, `PetscViewer` 2556 @*/ 2557 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2558 { 2559 PetscBool ishdf5; 2560 2561 PetscFunctionBegin; 2562 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2563 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2564 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2565 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2566 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2567 if (ishdf5) { 2568 #if defined(PETSC_HAVE_HDF5) 2569 PetscViewerFormat format; 2570 2571 PetscCall(PetscViewerGetFormat(viewer, &format)); 2572 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2573 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2574 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2575 #else 2576 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2577 #endif 2578 } 2579 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2580 PetscFunctionReturn(PETSC_SUCCESS); 2581 } 2582 2583 /*@ 2584 DMPlexSectionLoad - Loads section into a `DMPLEX` 2585 2586 Collective 2587 2588 Input Parameters: 2589 + dm - The `DM` that represents the topology 2590 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2591 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2592 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2593 2594 Output Parameters: 2595 + 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) 2596 - 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) 2597 2598 Level: advanced 2599 2600 Notes: 2601 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. 2602 2603 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. 2604 2605 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. 2606 2607 Example using 2 processes: 2608 .vb 2609 NX (number of points on dm): 4 2610 sectionA : the on-disk section 2611 vecA : a vector associated with sectionA 2612 sectionB : sectiondm's local section constructed in this function 2613 vecB (local) : a vector associated with sectiondm's local section 2614 vecB (global) : a vector associated with sectiondm's global section 2615 2616 rank 0 rank 1 2617 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2618 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2619 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2620 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2621 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2622 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2623 sectionB->atlasDof : 1 0 1 | 1 3 2624 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2625 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2626 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2627 .ve 2628 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2629 2630 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2631 @*/ 2632 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2633 { 2634 PetscBool ishdf5; 2635 2636 PetscFunctionBegin; 2637 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2638 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2639 if (!sectiondm) sectiondm = dm; 2640 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2641 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2642 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2643 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2644 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2645 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2646 if (ishdf5) { 2647 #if defined(PETSC_HAVE_HDF5) 2648 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2649 #else 2650 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2651 #endif 2652 } 2653 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2654 PetscFunctionReturn(PETSC_SUCCESS); 2655 } 2656 2657 /*@ 2658 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2659 2660 Collective 2661 2662 Input Parameters: 2663 + dm - The `DM` that represents the topology 2664 . viewer - The `PetscViewer` that represents the on-disk vector data 2665 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2666 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2667 - vec - The global vector to set values of 2668 2669 Level: advanced 2670 2671 Notes: 2672 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. 2673 2674 Calling sequence: 2675 .vb 2676 DMCreate(PETSC_COMM_WORLD, &dm); 2677 DMSetType(dm, DMPLEX); 2678 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2679 DMPlexTopologyLoad(dm, viewer, &sfX); 2680 DMClone(dm, §iondm); 2681 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2682 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2683 DMGetGlobalVector(sectiondm, &vec); 2684 PetscObjectSetName((PetscObject)vec, "vec_name"); 2685 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2686 DMRestoreGlobalVector(sectiondm, &vec); 2687 PetscSFDestroy(&gsf); 2688 PetscSFDestroy(&sfX); 2689 DMDestroy(§iondm); 2690 DMDestroy(&dm); 2691 .ve 2692 2693 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2694 `PetscSF`, `PetscViewer` 2695 @*/ 2696 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2697 { 2698 PetscBool ishdf5; 2699 2700 PetscFunctionBegin; 2701 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2702 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2703 if (!sectiondm) sectiondm = dm; 2704 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2705 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2706 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2707 /* Check consistency */ 2708 { 2709 PetscSection section; 2710 PetscBool includesConstraints; 2711 PetscInt m, m1; 2712 2713 PetscCall(VecGetLocalSize(vec, &m1)); 2714 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2715 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2716 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2717 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2718 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2719 } 2720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2721 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2722 if (ishdf5) { 2723 #if defined(PETSC_HAVE_HDF5) 2724 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2725 #else 2726 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2727 #endif 2728 } 2729 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2730 PetscFunctionReturn(PETSC_SUCCESS); 2731 } 2732 2733 /*@ 2734 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2735 2736 Collective 2737 2738 Input Parameters: 2739 + dm - The `DM` that represents the topology 2740 . viewer - The `PetscViewer` that represents the on-disk vector data 2741 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2742 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2743 - vec - The local vector to set values of 2744 2745 Level: advanced 2746 2747 Notes: 2748 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. 2749 2750 Calling sequence: 2751 .vb 2752 DMCreate(PETSC_COMM_WORLD, &dm); 2753 DMSetType(dm, DMPLEX); 2754 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2755 DMPlexTopologyLoad(dm, viewer, &sfX); 2756 DMClone(dm, §iondm); 2757 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2758 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2759 DMGetLocalVector(sectiondm, &vec); 2760 PetscObjectSetName((PetscObject)vec, "vec_name"); 2761 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2762 DMRestoreLocalVector(sectiondm, &vec); 2763 PetscSFDestroy(&lsf); 2764 PetscSFDestroy(&sfX); 2765 DMDestroy(§iondm); 2766 DMDestroy(&dm); 2767 .ve 2768 2769 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2770 `PetscSF`, `PetscViewer` 2771 @*/ 2772 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2773 { 2774 PetscBool ishdf5; 2775 2776 PetscFunctionBegin; 2777 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2778 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2779 if (!sectiondm) sectiondm = dm; 2780 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2781 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2782 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2783 /* Check consistency */ 2784 { 2785 PetscSection section; 2786 PetscBool includesConstraints; 2787 PetscInt m, m1; 2788 2789 PetscCall(VecGetLocalSize(vec, &m1)); 2790 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2791 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2792 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2793 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2794 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2795 } 2796 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2797 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2798 if (ishdf5) { 2799 #if defined(PETSC_HAVE_HDF5) 2800 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2801 #else 2802 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2803 #endif 2804 } 2805 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2806 PetscFunctionReturn(PETSC_SUCCESS); 2807 } 2808 2809 PetscErrorCode DMDestroy_Plex(DM dm) 2810 { 2811 DM_Plex *mesh = (DM_Plex *)dm->data; 2812 2813 PetscFunctionBegin; 2814 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2815 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2816 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2817 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2818 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2819 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2820 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2821 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2822 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2823 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2824 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2825 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2826 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2827 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2828 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2829 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2830 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2831 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2832 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2833 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2834 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2835 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2836 PetscCall(PetscFree(mesh->cones)); 2837 PetscCall(PetscFree(mesh->coneOrientations)); 2838 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2839 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2840 PetscCall(PetscFree(mesh->supports)); 2841 PetscCall(PetscFree(mesh->cellTypes)); 2842 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2843 PetscCall(PetscFree(mesh->tetgenOpts)); 2844 PetscCall(PetscFree(mesh->triangleOpts)); 2845 PetscCall(PetscFree(mesh->transformType)); 2846 PetscCall(PetscFree(mesh->distributionName)); 2847 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2848 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2849 PetscCall(ISDestroy(&mesh->subpointIS)); 2850 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2851 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2852 if (mesh->periodic.face_sfs) { 2853 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2854 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2855 } 2856 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2857 if (mesh->periodic.periodic_points) { 2858 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2859 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2860 } 2861 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2862 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2863 PetscCall(ISDestroy(&mesh->anchorIS)); 2864 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2865 PetscCall(PetscFree(mesh->parents)); 2866 PetscCall(PetscFree(mesh->childIDs)); 2867 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2868 PetscCall(PetscFree(mesh->children)); 2869 PetscCall(DMDestroy(&mesh->referenceTree)); 2870 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2871 PetscCall(PetscFree(mesh->neighbors)); 2872 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2873 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2874 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2875 PetscCall(PetscFree(mesh)); 2876 PetscFunctionReturn(PETSC_SUCCESS); 2877 } 2878 2879 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2880 { 2881 PetscSection sectionGlobal, sectionLocal; 2882 PetscInt bs = -1, mbs; 2883 PetscInt localSize, localStart = 0; 2884 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2885 MatType mtype; 2886 ISLocalToGlobalMapping ltog; 2887 2888 PetscFunctionBegin; 2889 PetscCall(MatInitializePackage()); 2890 mtype = dm->mattype; 2891 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2892 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2893 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2894 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2895 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2896 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2897 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2898 PetscCall(MatSetType(*J, mtype)); 2899 PetscCall(MatSetFromOptions(*J)); 2900 PetscCall(MatGetBlockSize(*J, &mbs)); 2901 if (mbs > 1) bs = mbs; 2902 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2903 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2904 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2905 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2906 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2907 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2908 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2909 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2910 if (!isShell) { 2911 // There are three states with pblocks, since block starts can have no dofs: 2912 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2913 // TRUE) Block Start: The first entry in a block has been added 2914 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2915 PetscBT blst; 2916 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2917 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2918 const PetscInt *perm = NULL; 2919 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2920 PetscInt pStart, pEnd, dof, cdof, num_fields; 2921 2922 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2923 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2924 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2925 2926 PetscCall(PetscCalloc1(localSize, &pblocks)); 2927 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2928 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2929 // We need to process in the permuted order to get block sizes right 2930 for (PetscInt point = pStart; point < pEnd; ++point) { 2931 const PetscInt p = perm ? perm[point] : point; 2932 2933 switch (dm->blocking_type) { 2934 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2935 PetscInt bdof, offset; 2936 2937 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2938 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2939 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2940 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2941 if (dof > 0) { 2942 // State change 2943 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2944 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2945 2946 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2947 // Signal block concatenation 2948 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2949 } 2950 dof = dof < 0 ? -(dof + 1) : dof; 2951 bdof = cdof && (dof - cdof) ? 1 : dof; 2952 if (dof) { 2953 if (bs < 0) { 2954 bs = bdof; 2955 } else if (bs != bdof) { 2956 bs = 1; 2957 } 2958 } 2959 } break; 2960 case DM_BLOCKING_FIELD_NODE: { 2961 for (PetscInt field = 0; field < num_fields; field++) { 2962 PetscInt num_comp, bdof, offset; 2963 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2964 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2965 if (dof < 0) continue; 2966 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2967 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2968 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); 2969 PetscInt num_nodes = dof / num_comp; 2970 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2971 // Handle possibly constant block size (unlikely) 2972 bdof = cdof && (dof - cdof) ? 1 : dof; 2973 if (dof) { 2974 if (bs < 0) { 2975 bs = bdof; 2976 } else if (bs != bdof) { 2977 bs = 1; 2978 } 2979 } 2980 } 2981 } break; 2982 } 2983 } 2984 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2985 /* Must have same blocksize on all procs (some might have no points) */ 2986 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 2987 bsLocal[1] = bs; 2988 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2989 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2990 else bs = bsMinMax[0]; 2991 bs = PetscMax(1, bs); 2992 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2993 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2994 PetscCall(MatSetBlockSize(*J, bs)); 2995 PetscCall(MatSetUp(*J)); 2996 } else { 2997 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2998 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2999 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 3000 } 3001 if (pblocks) { // Consolidate blocks 3002 PetscInt nblocks = 0; 3003 pblocks[0] = PetscAbs(pblocks[0]); 3004 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 3005 if (pblocks[i] == 0) continue; 3006 // Negative block size indicates the blocks should be concatenated 3007 if (pblocks[i] < 0) { 3008 pblocks[i] = -pblocks[i]; 3009 pblocks[nblocks - 1] += pblocks[i]; 3010 } else { 3011 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 3012 } 3013 for (PetscInt j = 1; j < pblocks[i]; j++) 3014 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); 3015 } 3016 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 3017 } 3018 PetscCall(PetscFree(pblocks)); 3019 } 3020 PetscCall(MatSetDM(*J, dm)); 3021 PetscFunctionReturn(PETSC_SUCCESS); 3022 } 3023 3024 /*@ 3025 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 3026 3027 Not Collective 3028 3029 Input Parameter: 3030 . dm - The `DMPLEX` 3031 3032 Output Parameter: 3033 . subsection - The subdomain section 3034 3035 Level: developer 3036 3037 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 3038 @*/ 3039 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 3040 { 3041 DM_Plex *mesh = (DM_Plex *)dm->data; 3042 3043 PetscFunctionBegin; 3044 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3045 if (!mesh->subdomainSection) { 3046 PetscSection section; 3047 PetscSF sf; 3048 3049 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 3050 PetscCall(DMGetLocalSection(dm, §ion)); 3051 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 3052 PetscCall(PetscSFDestroy(&sf)); 3053 } 3054 *subsection = mesh->subdomainSection; 3055 PetscFunctionReturn(PETSC_SUCCESS); 3056 } 3057 3058 /*@ 3059 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 3060 3061 Not Collective 3062 3063 Input Parameter: 3064 . dm - The `DMPLEX` 3065 3066 Output Parameters: 3067 + pStart - The first mesh point 3068 - pEnd - The upper bound for mesh points 3069 3070 Level: beginner 3071 3072 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3073 @*/ 3074 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3075 { 3076 DM_Plex *mesh = (DM_Plex *)dm->data; 3077 3078 PetscFunctionBegin; 3079 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3080 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3081 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3082 PetscFunctionReturn(PETSC_SUCCESS); 3083 } 3084 3085 /*@ 3086 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3087 3088 Not Collective 3089 3090 Input Parameters: 3091 + dm - The `DMPLEX` 3092 . pStart - The first mesh point 3093 - pEnd - The upper bound for mesh points 3094 3095 Level: beginner 3096 3097 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3098 @*/ 3099 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3100 { 3101 DM_Plex *mesh = (DM_Plex *)dm->data; 3102 3103 PetscFunctionBegin; 3104 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3105 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3106 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3107 PetscCall(PetscFree(mesh->cellTypes)); 3108 PetscFunctionReturn(PETSC_SUCCESS); 3109 } 3110 3111 /*@ 3112 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3113 3114 Not Collective 3115 3116 Input Parameters: 3117 + dm - The `DMPLEX` 3118 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3119 3120 Output Parameter: 3121 . size - The cone size for point `p` 3122 3123 Level: beginner 3124 3125 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3126 @*/ 3127 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3128 { 3129 DM_Plex *mesh = (DM_Plex *)dm->data; 3130 3131 PetscFunctionBegin; 3132 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3133 PetscAssertPointer(size, 3); 3134 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3135 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3136 PetscFunctionReturn(PETSC_SUCCESS); 3137 } 3138 3139 /*@ 3140 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3141 3142 Not Collective 3143 3144 Input Parameters: 3145 + dm - The `DMPLEX` 3146 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3147 - size - The cone size for point `p` 3148 3149 Level: beginner 3150 3151 Note: 3152 This should be called after `DMPlexSetChart()`. 3153 3154 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3155 @*/ 3156 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3157 { 3158 DM_Plex *mesh = (DM_Plex *)dm->data; 3159 3160 PetscFunctionBegin; 3161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3162 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3163 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3164 PetscFunctionReturn(PETSC_SUCCESS); 3165 } 3166 3167 /*@C 3168 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3169 3170 Not Collective 3171 3172 Input Parameters: 3173 + dm - The `DMPLEX` 3174 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3175 3176 Output Parameter: 3177 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3178 3179 Level: beginner 3180 3181 Fortran Notes: 3182 `cone` must be declared with 3183 .vb 3184 PetscInt, pointer :: cone(:) 3185 .ve 3186 3187 You must also call `DMPlexRestoreCone()` after you finish using the array. 3188 `DMPlexRestoreCone()` is not needed/available in C. 3189 3190 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3191 @*/ 3192 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3193 { 3194 DM_Plex *mesh = (DM_Plex *)dm->data; 3195 PetscInt off; 3196 3197 PetscFunctionBegin; 3198 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3199 PetscAssertPointer(cone, 3); 3200 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3201 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3202 PetscFunctionReturn(PETSC_SUCCESS); 3203 } 3204 3205 /*@ 3206 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3207 3208 Not Collective 3209 3210 Input Parameters: 3211 + dm - The `DMPLEX` 3212 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3213 3214 Output Parameters: 3215 + pConesSection - `PetscSection` describing the layout of `pCones` 3216 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3217 3218 Level: intermediate 3219 3220 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3221 @*/ 3222 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3223 { 3224 PetscSection cs, newcs; 3225 PetscInt *cones; 3226 PetscInt *newarr = NULL; 3227 PetscInt n; 3228 3229 PetscFunctionBegin; 3230 PetscCall(DMPlexGetCones(dm, &cones)); 3231 PetscCall(DMPlexGetConeSection(dm, &cs)); 3232 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3233 if (pConesSection) *pConesSection = newcs; 3234 if (pCones) { 3235 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3236 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3237 } 3238 PetscFunctionReturn(PETSC_SUCCESS); 3239 } 3240 3241 /*@ 3242 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3243 3244 Not Collective 3245 3246 Input Parameters: 3247 + dm - The `DMPLEX` 3248 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3249 3250 Output Parameter: 3251 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3252 3253 Level: advanced 3254 3255 Notes: 3256 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3257 3258 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3259 3260 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3261 `DMPlexGetDepth()`, `IS` 3262 @*/ 3263 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3264 { 3265 IS *expandedPointsAll; 3266 PetscInt depth; 3267 3268 PetscFunctionBegin; 3269 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3270 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3271 PetscAssertPointer(expandedPoints, 3); 3272 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3273 *expandedPoints = expandedPointsAll[0]; 3274 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3275 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3276 PetscFunctionReturn(PETSC_SUCCESS); 3277 } 3278 3279 /*@ 3280 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3281 (DAG points of depth 0, i.e., without cones). 3282 3283 Not Collective 3284 3285 Input Parameters: 3286 + dm - The `DMPLEX` 3287 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3288 3289 Output Parameters: 3290 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3291 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3292 - sections - (optional) An array of sections which describe mappings from points to their cone points 3293 3294 Level: advanced 3295 3296 Notes: 3297 Like `DMPlexGetConeTuple()` but recursive. 3298 3299 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. 3300 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3301 3302 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\: 3303 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3304 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3305 3306 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3307 `DMPlexGetDepth()`, `PetscSection`, `IS` 3308 @*/ 3309 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3310 { 3311 const PetscInt *arr0 = NULL, *cone = NULL; 3312 PetscInt *arr = NULL, *newarr = NULL; 3313 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3314 IS *expandedPoints_; 3315 PetscSection *sections_; 3316 3317 PetscFunctionBegin; 3318 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3319 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3320 if (depth) PetscAssertPointer(depth, 3); 3321 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3322 if (sections) PetscAssertPointer(sections, 5); 3323 PetscCall(ISGetLocalSize(points, &n)); 3324 PetscCall(ISGetIndices(points, &arr0)); 3325 PetscCall(DMPlexGetDepth(dm, &depth_)); 3326 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3327 PetscCall(PetscCalloc1(depth_, §ions_)); 3328 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3329 for (d = depth_ - 1; d >= 0; d--) { 3330 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3331 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3332 for (i = 0; i < n; i++) { 3333 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3334 if (arr[i] >= start && arr[i] < end) { 3335 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3336 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3337 } else { 3338 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3339 } 3340 } 3341 PetscCall(PetscSectionSetUp(sections_[d])); 3342 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3343 PetscCall(PetscMalloc1(newn, &newarr)); 3344 for (i = 0; i < n; i++) { 3345 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3346 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3347 if (cn > 1) { 3348 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3349 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3350 } else { 3351 newarr[co] = arr[i]; 3352 } 3353 } 3354 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3355 arr = newarr; 3356 n = newn; 3357 } 3358 PetscCall(ISRestoreIndices(points, &arr0)); 3359 *depth = depth_; 3360 if (expandedPoints) *expandedPoints = expandedPoints_; 3361 else { 3362 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3363 PetscCall(PetscFree(expandedPoints_)); 3364 } 3365 if (sections) *sections = sections_; 3366 else { 3367 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3368 PetscCall(PetscFree(sections_)); 3369 } 3370 PetscFunctionReturn(PETSC_SUCCESS); 3371 } 3372 3373 /*@ 3374 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3375 3376 Not Collective 3377 3378 Input Parameters: 3379 + dm - The `DMPLEX` 3380 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3381 3382 Output Parameters: 3383 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3384 . expandedPoints - (optional) An array of recursively expanded cones 3385 - sections - (optional) An array of sections which describe mappings from points to their cone points 3386 3387 Level: advanced 3388 3389 Note: 3390 See `DMPlexGetConeRecursive()` 3391 3392 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3393 `DMPlexGetDepth()`, `IS`, `PetscSection` 3394 @*/ 3395 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3396 { 3397 PetscInt d, depth_; 3398 3399 PetscFunctionBegin; 3400 PetscCall(DMPlexGetDepth(dm, &depth_)); 3401 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3402 if (depth) *depth = 0; 3403 if (expandedPoints) { 3404 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3405 PetscCall(PetscFree(*expandedPoints)); 3406 } 3407 if (sections) { 3408 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3409 PetscCall(PetscFree(*sections)); 3410 } 3411 PetscFunctionReturn(PETSC_SUCCESS); 3412 } 3413 3414 /*@ 3415 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 3416 3417 Not Collective 3418 3419 Input Parameters: 3420 + dm - The `DMPLEX` 3421 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3422 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3423 3424 Level: beginner 3425 3426 Note: 3427 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3428 3429 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3430 @*/ 3431 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3432 { 3433 DM_Plex *mesh = (DM_Plex *)dm->data; 3434 PetscInt dof, off, c; 3435 3436 PetscFunctionBegin; 3437 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3438 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3439 if (dof) PetscAssertPointer(cone, 3); 3440 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3441 if (PetscDefined(USE_DEBUG)) { 3442 PetscInt pStart, pEnd; 3443 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3444 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); 3445 for (c = 0; c < dof; ++c) { 3446 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); 3447 mesh->cones[off + c] = cone[c]; 3448 } 3449 } else { 3450 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3451 } 3452 PetscFunctionReturn(PETSC_SUCCESS); 3453 } 3454 3455 /*@C 3456 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3457 3458 Not Collective 3459 3460 Input Parameters: 3461 + dm - The `DMPLEX` 3462 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3463 3464 Output Parameter: 3465 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3466 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3467 3468 Level: beginner 3469 3470 Note: 3471 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3472 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3473 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3474 with the identity. 3475 3476 Fortran Notes: 3477 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3478 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3479 3480 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3481 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3482 @*/ 3483 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3484 { 3485 DM_Plex *mesh = (DM_Plex *)dm->data; 3486 PetscInt off; 3487 3488 PetscFunctionBegin; 3489 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3490 if (PetscDefined(USE_DEBUG)) { 3491 PetscInt dof; 3492 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3493 if (dof) PetscAssertPointer(coneOrientation, 3); 3494 } 3495 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3496 3497 *coneOrientation = &mesh->coneOrientations[off]; 3498 PetscFunctionReturn(PETSC_SUCCESS); 3499 } 3500 3501 /*@ 3502 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3503 3504 Not Collective 3505 3506 Input Parameters: 3507 + dm - The `DMPLEX` 3508 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3509 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3510 3511 Level: beginner 3512 3513 Notes: 3514 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3515 3516 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3517 3518 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3519 @*/ 3520 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3521 { 3522 DM_Plex *mesh = (DM_Plex *)dm->data; 3523 PetscInt pStart, pEnd; 3524 PetscInt dof, off, c; 3525 3526 PetscFunctionBegin; 3527 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3528 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3529 if (dof) PetscAssertPointer(coneOrientation, 3); 3530 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3531 if (PetscDefined(USE_DEBUG)) { 3532 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3533 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); 3534 for (c = 0; c < dof; ++c) { 3535 PetscInt cdof, o = coneOrientation[c]; 3536 3537 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3538 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); 3539 mesh->coneOrientations[off + c] = o; 3540 } 3541 } else { 3542 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3543 } 3544 PetscFunctionReturn(PETSC_SUCCESS); 3545 } 3546 3547 /*@ 3548 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3549 3550 Not Collective 3551 3552 Input Parameters: 3553 + dm - The `DMPLEX` 3554 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3555 . conePos - The local index in the cone where the point should be put 3556 - conePoint - The mesh point to insert 3557 3558 Level: beginner 3559 3560 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3561 @*/ 3562 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3563 { 3564 DM_Plex *mesh = (DM_Plex *)dm->data; 3565 PetscInt pStart, pEnd; 3566 PetscInt dof, off; 3567 3568 PetscFunctionBegin; 3569 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3570 if (PetscDefined(USE_DEBUG)) { 3571 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3572 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); 3573 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); 3574 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3575 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); 3576 } 3577 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3578 mesh->cones[off + conePos] = conePoint; 3579 PetscFunctionReturn(PETSC_SUCCESS); 3580 } 3581 3582 /*@ 3583 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3584 3585 Not Collective 3586 3587 Input Parameters: 3588 + dm - The `DMPLEX` 3589 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3590 . conePos - The local index in the cone where the point should be put 3591 - coneOrientation - The point orientation to insert 3592 3593 Level: beginner 3594 3595 Note: 3596 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3597 3598 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3599 @*/ 3600 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3601 { 3602 DM_Plex *mesh = (DM_Plex *)dm->data; 3603 PetscInt pStart, pEnd; 3604 PetscInt dof, off; 3605 3606 PetscFunctionBegin; 3607 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3608 if (PetscDefined(USE_DEBUG)) { 3609 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3610 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); 3611 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3612 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); 3613 } 3614 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3615 mesh->coneOrientations[off + conePos] = coneOrientation; 3616 PetscFunctionReturn(PETSC_SUCCESS); 3617 } 3618 3619 /*@C 3620 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3621 3622 Not collective 3623 3624 Input Parameters: 3625 + dm - The DMPlex 3626 - p - The point, which must lie in the chart set with DMPlexSetChart() 3627 3628 Output Parameters: 3629 + cone - An array of points which are on the in-edges for point `p` 3630 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3631 integer giving the prescription for cone traversal. 3632 3633 Level: beginner 3634 3635 Notes: 3636 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3637 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3638 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3639 with the identity. 3640 3641 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3642 3643 Fortran Notes: 3644 `cone` and `ornt` must be declared with 3645 .vb 3646 PetscInt, pointer :: cone(:) 3647 PetscInt, pointer :: ornt(:) 3648 .ve 3649 3650 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3651 @*/ 3652 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3653 { 3654 DM_Plex *mesh = (DM_Plex *)dm->data; 3655 3656 PetscFunctionBegin; 3657 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3658 if (mesh->tr) { 3659 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3660 } else { 3661 PetscInt off; 3662 if (PetscDefined(USE_DEBUG)) { 3663 PetscInt dof; 3664 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3665 if (dof) { 3666 if (cone) PetscAssertPointer(cone, 3); 3667 if (ornt) PetscAssertPointer(ornt, 4); 3668 } 3669 } 3670 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3671 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3672 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3673 } 3674 PetscFunctionReturn(PETSC_SUCCESS); 3675 } 3676 3677 /*@C 3678 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3679 3680 Not Collective 3681 3682 Input Parameters: 3683 + dm - The DMPlex 3684 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3685 . cone - An array of points which are on the in-edges for point p 3686 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3687 integer giving the prescription for cone traversal. 3688 3689 Level: beginner 3690 3691 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3692 @*/ 3693 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3694 { 3695 DM_Plex *mesh = (DM_Plex *)dm->data; 3696 3697 PetscFunctionBegin; 3698 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3699 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3700 PetscFunctionReturn(PETSC_SUCCESS); 3701 } 3702 3703 /*@ 3704 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3705 3706 Not Collective 3707 3708 Input Parameters: 3709 + dm - The `DMPLEX` 3710 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3711 3712 Output Parameter: 3713 . size - The support size for point `p` 3714 3715 Level: beginner 3716 3717 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3718 @*/ 3719 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3720 { 3721 DM_Plex *mesh = (DM_Plex *)dm->data; 3722 3723 PetscFunctionBegin; 3724 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3725 PetscAssertPointer(size, 3); 3726 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3727 PetscFunctionReturn(PETSC_SUCCESS); 3728 } 3729 3730 /*@ 3731 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3732 3733 Not Collective 3734 3735 Input Parameters: 3736 + dm - The `DMPLEX` 3737 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3738 - size - The support size for point `p` 3739 3740 Level: beginner 3741 3742 Note: 3743 This should be called after `DMPlexSetChart()`. 3744 3745 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3746 @*/ 3747 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3748 { 3749 DM_Plex *mesh = (DM_Plex *)dm->data; 3750 3751 PetscFunctionBegin; 3752 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3753 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3754 PetscFunctionReturn(PETSC_SUCCESS); 3755 } 3756 3757 /*@C 3758 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3759 3760 Not Collective 3761 3762 Input Parameters: 3763 + dm - The `DMPLEX` 3764 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3765 3766 Output Parameter: 3767 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3768 3769 Level: beginner 3770 3771 Fortran Notes: 3772 `support` must be declared with 3773 .vb 3774 PetscInt, pointer :: support(:) 3775 .ve 3776 3777 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3778 `DMPlexRestoreSupport()` is not needed/available in C. 3779 3780 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3781 @*/ 3782 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3783 { 3784 DM_Plex *mesh = (DM_Plex *)dm->data; 3785 PetscInt off; 3786 3787 PetscFunctionBegin; 3788 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3789 PetscAssertPointer(support, 3); 3790 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3791 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3792 PetscFunctionReturn(PETSC_SUCCESS); 3793 } 3794 3795 /*@ 3796 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3797 3798 Not Collective 3799 3800 Input Parameters: 3801 + dm - The `DMPLEX` 3802 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3803 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3804 3805 Level: beginner 3806 3807 Note: 3808 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3809 3810 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3811 @*/ 3812 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3813 { 3814 DM_Plex *mesh = (DM_Plex *)dm->data; 3815 PetscInt pStart, pEnd; 3816 PetscInt dof, off, c; 3817 3818 PetscFunctionBegin; 3819 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3820 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3821 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3822 if (dof) PetscAssertPointer(support, 3); 3823 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3824 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); 3825 for (c = 0; c < dof; ++c) { 3826 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); 3827 mesh->supports[off + c] = support[c]; 3828 } 3829 PetscFunctionReturn(PETSC_SUCCESS); 3830 } 3831 3832 /*@ 3833 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3834 3835 Not Collective 3836 3837 Input Parameters: 3838 + dm - The `DMPLEX` 3839 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3840 . supportPos - The local index in the cone where the point should be put 3841 - supportPoint - The mesh point to insert 3842 3843 Level: beginner 3844 3845 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3846 @*/ 3847 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3848 { 3849 DM_Plex *mesh = (DM_Plex *)dm->data; 3850 PetscInt pStart, pEnd; 3851 PetscInt dof, off; 3852 3853 PetscFunctionBegin; 3854 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3855 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3856 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3857 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3858 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); 3859 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); 3860 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); 3861 mesh->supports[off + supportPos] = supportPoint; 3862 PetscFunctionReturn(PETSC_SUCCESS); 3863 } 3864 3865 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3866 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3867 { 3868 switch (ct) { 3869 case DM_POLYTOPE_SEGMENT: 3870 if (o == -1) return -2; 3871 break; 3872 case DM_POLYTOPE_TRIANGLE: 3873 if (o == -3) return -1; 3874 if (o == -2) return -3; 3875 if (o == -1) return -2; 3876 break; 3877 case DM_POLYTOPE_QUADRILATERAL: 3878 if (o == -4) return -2; 3879 if (o == -3) return -1; 3880 if (o == -2) return -4; 3881 if (o == -1) return -3; 3882 break; 3883 default: 3884 return o; 3885 } 3886 return o; 3887 } 3888 3889 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3890 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3891 { 3892 switch (ct) { 3893 case DM_POLYTOPE_SEGMENT: 3894 if ((o == -2) || (o == 1)) return -1; 3895 if (o == -1) return 0; 3896 break; 3897 case DM_POLYTOPE_TRIANGLE: 3898 if (o == -3) return -2; 3899 if (o == -2) return -1; 3900 if (o == -1) return -3; 3901 break; 3902 case DM_POLYTOPE_QUADRILATERAL: 3903 if (o == -4) return -2; 3904 if (o == -3) return -1; 3905 if (o == -2) return -4; 3906 if (o == -1) return -3; 3907 break; 3908 default: 3909 return o; 3910 } 3911 return o; 3912 } 3913 3914 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3915 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3916 { 3917 PetscInt pStart, pEnd, p; 3918 3919 PetscFunctionBegin; 3920 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3921 for (p = pStart; p < pEnd; ++p) { 3922 const PetscInt *cone, *ornt; 3923 PetscInt coneSize, c; 3924 3925 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3926 PetscCall(DMPlexGetCone(dm, p, &cone)); 3927 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3928 for (c = 0; c < coneSize; ++c) { 3929 DMPolytopeType ct; 3930 const PetscInt o = ornt[c]; 3931 3932 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3933 switch (ct) { 3934 case DM_POLYTOPE_SEGMENT: 3935 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3936 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3937 break; 3938 case DM_POLYTOPE_TRIANGLE: 3939 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3940 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3941 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3942 break; 3943 case DM_POLYTOPE_QUADRILATERAL: 3944 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3945 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3946 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3947 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3948 break; 3949 default: 3950 break; 3951 } 3952 } 3953 } 3954 PetscFunctionReturn(PETSC_SUCCESS); 3955 } 3956 3957 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3958 { 3959 DM_Plex *mesh = (DM_Plex *)dm->data; 3960 3961 PetscFunctionBeginHot; 3962 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3963 if (useCone) { 3964 PetscCall(DMPlexGetConeSize(dm, p, size)); 3965 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3966 } else { 3967 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3968 PetscCall(DMPlexGetSupport(dm, p, arr)); 3969 } 3970 } else { 3971 if (useCone) { 3972 const PetscSection s = mesh->coneSection; 3973 const PetscInt ps = p - s->pStart; 3974 const PetscInt off = s->atlasOff[ps]; 3975 3976 *size = s->atlasDof[ps]; 3977 *arr = mesh->cones + off; 3978 *ornt = mesh->coneOrientations + off; 3979 } else { 3980 const PetscSection s = mesh->supportSection; 3981 const PetscInt ps = p - s->pStart; 3982 const PetscInt off = s->atlasOff[ps]; 3983 3984 *size = s->atlasDof[ps]; 3985 *arr = mesh->supports + off; 3986 } 3987 } 3988 PetscFunctionReturn(PETSC_SUCCESS); 3989 } 3990 3991 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3992 { 3993 DM_Plex *mesh = (DM_Plex *)dm->data; 3994 3995 PetscFunctionBeginHot; 3996 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3997 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3998 } 3999 PetscFunctionReturn(PETSC_SUCCESS); 4000 } 4001 4002 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4003 { 4004 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4005 PetscInt *closure; 4006 const PetscInt *tmp = NULL, *tmpO = NULL; 4007 PetscInt off = 0, tmpSize, t; 4008 4009 PetscFunctionBeginHot; 4010 if (ornt) { 4011 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4012 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; 4013 } 4014 if (*points) { 4015 closure = *points; 4016 } else { 4017 PetscInt maxConeSize, maxSupportSize; 4018 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4019 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 4020 } 4021 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4022 if (ct == DM_POLYTOPE_UNKNOWN) { 4023 closure[off++] = p; 4024 closure[off++] = 0; 4025 for (t = 0; t < tmpSize; ++t) { 4026 closure[off++] = tmp[t]; 4027 closure[off++] = tmpO ? tmpO[t] : 0; 4028 } 4029 } else { 4030 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 4031 4032 /* We assume that cells with a valid type have faces with a valid type */ 4033 closure[off++] = p; 4034 closure[off++] = ornt; 4035 for (t = 0; t < tmpSize; ++t) { 4036 DMPolytopeType ft; 4037 4038 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 4039 closure[off++] = tmp[arr[t]]; 4040 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 4041 } 4042 } 4043 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4044 if (numPoints) *numPoints = tmpSize + 1; 4045 if (points) *points = closure; 4046 PetscFunctionReturn(PETSC_SUCCESS); 4047 } 4048 4049 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 4050 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 4051 { 4052 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 4053 const PetscInt *cone, *ornt; 4054 PetscInt *pts, *closure = NULL; 4055 DMPolytopeType ft; 4056 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 4057 PetscInt dim, coneSize, c, d, clSize, cl; 4058 4059 PetscFunctionBeginHot; 4060 PetscCall(DMGetDimension(dm, &dim)); 4061 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4062 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4063 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4064 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4065 maxSize = PetscMax(coneSeries, supportSeries); 4066 if (*points) { 4067 pts = *points; 4068 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4069 c = 0; 4070 pts[c++] = point; 4071 pts[c++] = o; 4072 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4073 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4074 for (cl = 0; cl < clSize * 2; cl += 2) { 4075 pts[c++] = closure[cl]; 4076 pts[c++] = closure[cl + 1]; 4077 } 4078 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4079 for (cl = 0; cl < clSize * 2; cl += 2) { 4080 pts[c++] = closure[cl]; 4081 pts[c++] = closure[cl + 1]; 4082 } 4083 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4084 for (d = 2; d < coneSize; ++d) { 4085 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4086 pts[c++] = cone[arr[d * 2 + 0]]; 4087 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4088 } 4089 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4090 if (dim >= 3) { 4091 for (d = 2; d < coneSize; ++d) { 4092 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4093 const PetscInt *fcone, *fornt; 4094 PetscInt fconeSize, fc, i; 4095 4096 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4097 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4098 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4099 for (fc = 0; fc < fconeSize; ++fc) { 4100 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4101 const PetscInt co = farr[fc * 2 + 1]; 4102 4103 for (i = 0; i < c; i += 2) 4104 if (pts[i] == cp) break; 4105 if (i == c) { 4106 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4107 pts[c++] = cp; 4108 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4109 } 4110 } 4111 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4112 } 4113 } 4114 *numPoints = c / 2; 4115 *points = pts; 4116 PetscFunctionReturn(PETSC_SUCCESS); 4117 } 4118 4119 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4120 { 4121 DMPolytopeType ct; 4122 PetscInt *closure, *fifo; 4123 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4124 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4125 PetscInt depth, maxSize; 4126 4127 PetscFunctionBeginHot; 4128 PetscCall(DMPlexGetDepth(dm, &depth)); 4129 if (depth == 1) { 4130 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4131 PetscFunctionReturn(PETSC_SUCCESS); 4132 } 4133 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4134 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; 4135 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4136 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4137 PetscFunctionReturn(PETSC_SUCCESS); 4138 } 4139 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4140 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4141 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4142 maxSize = PetscMax(coneSeries, supportSeries); 4143 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4144 if (*points) { 4145 closure = *points; 4146 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4147 closure[closureSize++] = p; 4148 closure[closureSize++] = ornt; 4149 fifo[fifoSize++] = p; 4150 fifo[fifoSize++] = ornt; 4151 fifo[fifoSize++] = ct; 4152 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4153 while (fifoSize - fifoStart) { 4154 const PetscInt q = fifo[fifoStart++]; 4155 const PetscInt o = fifo[fifoStart++]; 4156 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4157 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4158 const PetscInt *tmp, *tmpO = NULL; 4159 PetscInt tmpSize, t; 4160 4161 if (PetscDefined(USE_DEBUG)) { 4162 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4163 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); 4164 } 4165 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4166 for (t = 0; t < tmpSize; ++t) { 4167 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4168 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4169 const PetscInt cp = tmp[ip]; 4170 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4171 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4172 PetscInt c; 4173 4174 /* Check for duplicate */ 4175 for (c = 0; c < closureSize; c += 2) { 4176 if (closure[c] == cp) break; 4177 } 4178 if (c == closureSize) { 4179 closure[closureSize++] = cp; 4180 closure[closureSize++] = co; 4181 fifo[fifoSize++] = cp; 4182 fifo[fifoSize++] = co; 4183 fifo[fifoSize++] = ct; 4184 } 4185 } 4186 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4187 } 4188 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4189 if (numPoints) *numPoints = closureSize / 2; 4190 if (points) *points = closure; 4191 PetscFunctionReturn(PETSC_SUCCESS); 4192 } 4193 4194 /*@C 4195 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4196 4197 Not Collective 4198 4199 Input Parameters: 4200 + dm - The `DMPLEX` 4201 . p - The mesh point 4202 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4203 4204 Input/Output Parameter: 4205 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4206 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4207 otherwise the provided array is used to hold the values 4208 4209 Output Parameter: 4210 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4211 4212 Level: beginner 4213 4214 Note: 4215 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4216 4217 Fortran Notes: 4218 `points` must be declared with 4219 .vb 4220 PetscInt, pointer :: points(:) 4221 .ve 4222 and is always allocated by the function. 4223 4224 The `numPoints` argument is not present in the Fortran binding. 4225 4226 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4227 @*/ 4228 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4229 { 4230 PetscFunctionBeginHot; 4231 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4232 if (numPoints) PetscAssertPointer(numPoints, 4); 4233 if (points) PetscAssertPointer(points, 5); 4234 if (PetscDefined(USE_DEBUG)) { 4235 PetscInt pStart, pEnd; 4236 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4237 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); 4238 } 4239 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4240 PetscFunctionReturn(PETSC_SUCCESS); 4241 } 4242 4243 /*@C 4244 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4245 4246 Not Collective 4247 4248 Input Parameters: 4249 + dm - The `DMPLEX` 4250 . p - The mesh point 4251 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4252 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4253 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4254 4255 Level: beginner 4256 4257 Note: 4258 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4259 4260 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4261 @*/ 4262 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4263 { 4264 PetscFunctionBeginHot; 4265 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4266 if (numPoints) *numPoints = 0; 4267 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4268 PetscFunctionReturn(PETSC_SUCCESS); 4269 } 4270 4271 /*@ 4272 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4273 4274 Not Collective 4275 4276 Input Parameter: 4277 . dm - The `DMPLEX` 4278 4279 Output Parameters: 4280 + maxConeSize - The maximum number of in-edges 4281 - maxSupportSize - The maximum number of out-edges 4282 4283 Level: beginner 4284 4285 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4286 @*/ 4287 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4288 { 4289 DM_Plex *mesh = (DM_Plex *)dm->data; 4290 4291 PetscFunctionBegin; 4292 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4293 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4294 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4295 PetscFunctionReturn(PETSC_SUCCESS); 4296 } 4297 4298 PetscErrorCode DMSetUp_Plex(DM dm) 4299 { 4300 DM_Plex *mesh = (DM_Plex *)dm->data; 4301 PetscInt size, maxSupportSize; 4302 4303 PetscFunctionBegin; 4304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4305 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4306 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4307 PetscCall(PetscMalloc1(size, &mesh->cones)); 4308 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4309 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4310 if (maxSupportSize) { 4311 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4312 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4313 PetscCall(PetscMalloc1(size, &mesh->supports)); 4314 } 4315 PetscFunctionReturn(PETSC_SUCCESS); 4316 } 4317 4318 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4319 { 4320 PetscFunctionBegin; 4321 if (subdm) PetscCall(DMClone(dm, subdm)); 4322 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4323 if (subdm) (*subdm)->useNatural = dm->useNatural; 4324 if (dm->useNatural && dm->sfMigration) { 4325 PetscSF sfNatural; 4326 4327 (*subdm)->sfMigration = dm->sfMigration; 4328 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4329 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4330 (*subdm)->sfNatural = sfNatural; 4331 } 4332 PetscFunctionReturn(PETSC_SUCCESS); 4333 } 4334 4335 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4336 { 4337 PetscInt i = 0; 4338 4339 PetscFunctionBegin; 4340 PetscCall(DMClone(dms[0], superdm)); 4341 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4342 (*superdm)->useNatural = PETSC_FALSE; 4343 for (i = 0; i < len; i++) { 4344 if (dms[i]->useNatural && dms[i]->sfMigration) { 4345 PetscSF sfNatural; 4346 4347 (*superdm)->sfMigration = dms[i]->sfMigration; 4348 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4349 (*superdm)->useNatural = PETSC_TRUE; 4350 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4351 (*superdm)->sfNatural = sfNatural; 4352 break; 4353 } 4354 } 4355 PetscFunctionReturn(PETSC_SUCCESS); 4356 } 4357 4358 /*@ 4359 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4360 4361 Not Collective 4362 4363 Input Parameter: 4364 . dm - The `DMPLEX` 4365 4366 Level: beginner 4367 4368 Note: 4369 This should be called after all calls to `DMPlexSetCone()` 4370 4371 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4372 @*/ 4373 PetscErrorCode DMPlexSymmetrize(DM dm) 4374 { 4375 DM_Plex *mesh = (DM_Plex *)dm->data; 4376 PetscInt *offsets; 4377 PetscInt supportSize; 4378 PetscInt pStart, pEnd, p; 4379 4380 PetscFunctionBegin; 4381 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4382 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4383 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4384 /* Calculate support sizes */ 4385 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4386 for (p = pStart; p < pEnd; ++p) { 4387 PetscInt dof, off, c; 4388 4389 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4390 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4391 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4392 } 4393 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4394 /* Calculate supports */ 4395 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4396 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4397 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 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) { 4404 const PetscInt q = mesh->cones[c]; 4405 PetscInt offS; 4406 4407 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4408 4409 mesh->supports[offS + offsets[q]] = p; 4410 ++offsets[q]; 4411 } 4412 } 4413 PetscCall(PetscFree(offsets)); 4414 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4415 PetscFunctionReturn(PETSC_SUCCESS); 4416 } 4417 4418 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4419 { 4420 IS stratumIS; 4421 4422 PetscFunctionBegin; 4423 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4424 if (PetscDefined(USE_DEBUG)) { 4425 PetscInt qStart, qEnd, numLevels, level; 4426 PetscBool overlap = PETSC_FALSE; 4427 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4428 for (level = 0; level < numLevels; level++) { 4429 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4430 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4431 overlap = PETSC_TRUE; 4432 break; 4433 } 4434 } 4435 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); 4436 } 4437 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4438 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4439 PetscCall(ISDestroy(&stratumIS)); 4440 PetscFunctionReturn(PETSC_SUCCESS); 4441 } 4442 4443 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4444 { 4445 PetscInt *pMin, *pMax; 4446 PetscInt pStart, pEnd; 4447 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4448 4449 PetscFunctionBegin; 4450 { 4451 DMLabel label2; 4452 4453 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4454 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4455 } 4456 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4457 for (PetscInt p = pStart; p < pEnd; ++p) { 4458 DMPolytopeType ct; 4459 4460 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4461 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4462 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4463 } 4464 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4465 for (PetscInt d = dmin; d <= dmax; ++d) { 4466 pMin[d] = PETSC_INT_MAX; 4467 pMax[d] = PETSC_INT_MIN; 4468 } 4469 for (PetscInt p = pStart; p < pEnd; ++p) { 4470 DMPolytopeType ct; 4471 PetscInt d; 4472 4473 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4474 d = DMPolytopeTypeGetDim(ct); 4475 pMin[d] = PetscMin(p, pMin[d]); 4476 pMax[d] = PetscMax(p, pMax[d]); 4477 } 4478 for (PetscInt d = dmin; d <= dmax; ++d) { 4479 if (pMin[d] > pMax[d]) continue; 4480 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4481 } 4482 PetscCall(PetscFree2(pMin, pMax)); 4483 PetscFunctionReturn(PETSC_SUCCESS); 4484 } 4485 4486 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4487 { 4488 PetscInt pStart, pEnd; 4489 PetscInt numRoots = 0, numLeaves = 0; 4490 4491 PetscFunctionBegin; 4492 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4493 { 4494 /* Initialize roots and count leaves */ 4495 PetscInt sMin = PETSC_INT_MAX; 4496 PetscInt sMax = PETSC_INT_MIN; 4497 PetscInt coneSize, supportSize; 4498 4499 for (PetscInt p = pStart; p < pEnd; ++p) { 4500 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4501 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4502 if (!coneSize && supportSize) { 4503 sMin = PetscMin(p, sMin); 4504 sMax = PetscMax(p, sMax); 4505 ++numRoots; 4506 } else if (!supportSize && coneSize) { 4507 ++numLeaves; 4508 } else if (!supportSize && !coneSize) { 4509 /* Isolated points */ 4510 sMin = PetscMin(p, sMin); 4511 sMax = PetscMax(p, sMax); 4512 } 4513 } 4514 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4515 } 4516 4517 if (numRoots + numLeaves == (pEnd - pStart)) { 4518 PetscInt sMin = PETSC_INT_MAX; 4519 PetscInt sMax = PETSC_INT_MIN; 4520 PetscInt coneSize, supportSize; 4521 4522 for (PetscInt p = pStart; p < pEnd; ++p) { 4523 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4524 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4525 if (!supportSize && coneSize) { 4526 sMin = PetscMin(p, sMin); 4527 sMax = PetscMax(p, sMax); 4528 } 4529 } 4530 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4531 } else { 4532 PetscInt level = 0; 4533 PetscInt qStart, qEnd; 4534 4535 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4536 while (qEnd > qStart) { 4537 PetscInt sMin = PETSC_INT_MAX; 4538 PetscInt sMax = PETSC_INT_MIN; 4539 4540 for (PetscInt q = qStart; q < qEnd; ++q) { 4541 const PetscInt *support; 4542 PetscInt supportSize; 4543 4544 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4545 PetscCall(DMPlexGetSupport(dm, q, &support)); 4546 for (PetscInt s = 0; s < supportSize; ++s) { 4547 sMin = PetscMin(support[s], sMin); 4548 sMax = PetscMax(support[s], sMax); 4549 } 4550 } 4551 PetscCall(DMLabelGetNumValues(label, &level)); 4552 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4553 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4554 } 4555 } 4556 PetscFunctionReturn(PETSC_SUCCESS); 4557 } 4558 4559 /*@ 4560 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4561 4562 Collective 4563 4564 Input Parameter: 4565 . dm - The `DMPLEX` 4566 4567 Level: beginner 4568 4569 Notes: 4570 The strata group all points of the same grade, and this function calculates the strata. This 4571 grade can be seen as the height (or depth) of the point in the DAG. 4572 4573 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4574 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4575 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4576 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4577 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4578 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4579 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4580 4581 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4582 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4583 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 4584 to interpolate only that one (e0), so that 4585 .vb 4586 cone(c0) = {e0, v2} 4587 cone(e0) = {v0, v1} 4588 .ve 4589 If `DMPlexStratify()` is run on this mesh, it will give depths 4590 .vb 4591 depth 0 = {v0, v1, v2} 4592 depth 1 = {e0, c0} 4593 .ve 4594 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4595 4596 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4597 4598 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4599 @*/ 4600 PetscErrorCode DMPlexStratify(DM dm) 4601 { 4602 DM_Plex *mesh = (DM_Plex *)dm->data; 4603 DMLabel label; 4604 PetscBool flg = PETSC_FALSE; 4605 4606 PetscFunctionBegin; 4607 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4608 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4609 4610 // Create depth label 4611 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4612 PetscCall(DMCreateLabel(dm, "depth")); 4613 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4614 4615 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4616 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4617 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4618 4619 { /* just in case there is an empty process */ 4620 PetscInt numValues, maxValues = 0, v; 4621 4622 PetscCall(DMLabelGetNumValues(label, &numValues)); 4623 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4624 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4625 } 4626 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4627 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4628 PetscFunctionReturn(PETSC_SUCCESS); 4629 } 4630 4631 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4632 { 4633 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4634 PetscInt dim, depth, pheight, coneSize; 4635 PetscBool preferTensor; 4636 4637 PetscFunctionBeginHot; 4638 PetscCall(DMGetDimension(dm, &dim)); 4639 PetscCall(DMPlexGetDepth(dm, &depth)); 4640 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4641 PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor)); 4642 pheight = depth - pdepth; 4643 if (depth <= 1) { 4644 switch (pdepth) { 4645 case 0: 4646 ct = DM_POLYTOPE_POINT; 4647 break; 4648 case 1: 4649 switch (coneSize) { 4650 case 2: 4651 ct = DM_POLYTOPE_SEGMENT; 4652 break; 4653 case 3: 4654 ct = DM_POLYTOPE_TRIANGLE; 4655 break; 4656 case 4: 4657 switch (dim) { 4658 case 2: 4659 ct = DM_POLYTOPE_QUADRILATERAL; 4660 break; 4661 case 3: 4662 ct = DM_POLYTOPE_TETRAHEDRON; 4663 break; 4664 default: 4665 break; 4666 } 4667 break; 4668 case 5: 4669 ct = DM_POLYTOPE_PYRAMID; 4670 break; 4671 case 6: 4672 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4673 break; 4674 case 8: 4675 ct = DM_POLYTOPE_HEXAHEDRON; 4676 break; 4677 default: 4678 break; 4679 } 4680 } 4681 } else { 4682 if (pdepth == 0) { 4683 ct = DM_POLYTOPE_POINT; 4684 } else if (pheight == 0) { 4685 switch (dim) { 4686 case 1: 4687 switch (coneSize) { 4688 case 2: 4689 ct = DM_POLYTOPE_SEGMENT; 4690 break; 4691 default: 4692 break; 4693 } 4694 break; 4695 case 2: 4696 switch (coneSize) { 4697 case 3: 4698 ct = DM_POLYTOPE_TRIANGLE; 4699 break; 4700 case 4: 4701 ct = DM_POLYTOPE_QUADRILATERAL; 4702 break; 4703 default: 4704 break; 4705 } 4706 break; 4707 case 3: 4708 switch (coneSize) { 4709 case 4: 4710 ct = DM_POLYTOPE_TETRAHEDRON; 4711 break; 4712 case 5: { 4713 const PetscInt *cone; 4714 PetscInt faceConeSize; 4715 4716 PetscCall(DMPlexGetCone(dm, p, &cone)); 4717 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4718 switch (faceConeSize) { 4719 case 3: 4720 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4721 break; 4722 case 4: 4723 ct = DM_POLYTOPE_PYRAMID; 4724 break; 4725 } 4726 } break; 4727 case 6: 4728 ct = DM_POLYTOPE_HEXAHEDRON; 4729 break; 4730 default: 4731 break; 4732 } 4733 break; 4734 default: 4735 break; 4736 } 4737 } else if (pheight > 0) { 4738 switch (coneSize) { 4739 case 2: 4740 ct = DM_POLYTOPE_SEGMENT; 4741 break; 4742 case 3: 4743 ct = DM_POLYTOPE_TRIANGLE; 4744 break; 4745 case 4: 4746 ct = DM_POLYTOPE_QUADRILATERAL; 4747 break; 4748 default: 4749 break; 4750 } 4751 } 4752 } 4753 *pt = ct; 4754 PetscFunctionReturn(PETSC_SUCCESS); 4755 } 4756 4757 /*@ 4758 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4759 4760 Collective 4761 4762 Input Parameter: 4763 . dm - The `DMPLEX` 4764 4765 Level: developer 4766 4767 Note: 4768 This function is normally called automatically when a cell type is requested. It creates an 4769 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4770 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4771 4772 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4773 4774 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4775 @*/ 4776 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4777 { 4778 DM_Plex *mesh; 4779 DMLabel ctLabel; 4780 PetscInt pStart, pEnd, p; 4781 4782 PetscFunctionBegin; 4783 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4784 mesh = (DM_Plex *)dm->data; 4785 PetscCall(DMCreateLabel(dm, "celltype")); 4786 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4787 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4788 PetscCall(PetscFree(mesh->cellTypes)); 4789 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4790 for (p = pStart; p < pEnd; ++p) { 4791 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4792 PetscInt pdepth; 4793 4794 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4795 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4796 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]); 4797 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4798 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4799 } 4800 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4801 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4802 PetscFunctionReturn(PETSC_SUCCESS); 4803 } 4804 4805 /*@C 4806 DMPlexGetJoin - Get an array for the join of the set of points 4807 4808 Not Collective 4809 4810 Input Parameters: 4811 + dm - The `DMPLEX` object 4812 . numPoints - The number of input points for the join 4813 - points - The input points 4814 4815 Output Parameters: 4816 + numCoveredPoints - The number of points in the join 4817 - coveredPoints - The points in the join 4818 4819 Level: intermediate 4820 4821 Note: 4822 Currently, this is restricted to a single level join 4823 4824 Fortran Notes: 4825 `converedPoints` must be declared with 4826 .vb 4827 PetscInt, pointer :: coveredPints(:) 4828 .ve 4829 4830 The `numCoveredPoints` argument is not present in the Fortran binding. 4831 4832 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4833 @*/ 4834 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4835 { 4836 DM_Plex *mesh = (DM_Plex *)dm->data; 4837 PetscInt *join[2]; 4838 PetscInt joinSize, i = 0; 4839 PetscInt dof, off, p, c, m; 4840 PetscInt maxSupportSize; 4841 4842 PetscFunctionBegin; 4843 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4844 PetscAssertPointer(points, 3); 4845 PetscAssertPointer(numCoveredPoints, 4); 4846 PetscAssertPointer(coveredPoints, 5); 4847 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4848 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4849 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4850 /* Copy in support of first point */ 4851 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4852 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4853 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4854 /* Check each successive support */ 4855 for (p = 1; p < numPoints; ++p) { 4856 PetscInt newJoinSize = 0; 4857 4858 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4859 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4860 for (c = 0; c < dof; ++c) { 4861 const PetscInt point = mesh->supports[off + c]; 4862 4863 for (m = 0; m < joinSize; ++m) { 4864 if (point == join[i][m]) { 4865 join[1 - i][newJoinSize++] = point; 4866 break; 4867 } 4868 } 4869 } 4870 joinSize = newJoinSize; 4871 i = 1 - i; 4872 } 4873 *numCoveredPoints = joinSize; 4874 *coveredPoints = join[i]; 4875 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4876 PetscFunctionReturn(PETSC_SUCCESS); 4877 } 4878 4879 /*@C 4880 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4881 4882 Not Collective 4883 4884 Input Parameters: 4885 + dm - The `DMPLEX` object 4886 . numPoints - The number of input points for the join 4887 - points - The input points 4888 4889 Output Parameters: 4890 + numCoveredPoints - The number of points in the join 4891 - coveredPoints - The points in the join 4892 4893 Level: intermediate 4894 4895 Fortran Notes: 4896 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4897 4898 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4899 @*/ 4900 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4901 { 4902 PetscFunctionBegin; 4903 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4904 if (points) PetscAssertPointer(points, 3); 4905 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4906 PetscAssertPointer(coveredPoints, 5); 4907 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4908 if (numCoveredPoints) *numCoveredPoints = 0; 4909 PetscFunctionReturn(PETSC_SUCCESS); 4910 } 4911 4912 /*@C 4913 DMPlexGetFullJoin - Get an array for the join of the set of points 4914 4915 Not Collective 4916 4917 Input Parameters: 4918 + dm - The `DMPLEX` object 4919 . numPoints - The number of input points for the join 4920 - points - The input points, its length is `numPoints` 4921 4922 Output Parameters: 4923 + numCoveredPoints - The number of points in the join 4924 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4925 4926 Level: intermediate 4927 4928 Fortran Notes: 4929 `points` and `converedPoints` must be declared with 4930 .vb 4931 PetscInt, pointer :: points(:) 4932 PetscInt, pointer :: coveredPints(:) 4933 .ve 4934 4935 The `numCoveredPoints` argument is not present in the Fortran binding. 4936 4937 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4938 @*/ 4939 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4940 { 4941 PetscInt *offsets, **closures; 4942 PetscInt *join[2]; 4943 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4944 PetscInt p, d, c, m, ms; 4945 4946 PetscFunctionBegin; 4947 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4948 PetscAssertPointer(points, 3); 4949 PetscAssertPointer(numCoveredPoints, 4); 4950 PetscAssertPointer(coveredPoints, 5); 4951 4952 PetscCall(DMPlexGetDepth(dm, &depth)); 4953 PetscCall(PetscCalloc1(numPoints, &closures)); 4954 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4955 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4956 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4957 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4958 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4959 4960 for (p = 0; p < numPoints; ++p) { 4961 PetscInt closureSize; 4962 4963 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4964 4965 offsets[p * (depth + 2) + 0] = 0; 4966 for (d = 0; d < depth + 1; ++d) { 4967 PetscInt pStart, pEnd, i; 4968 4969 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4970 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4971 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4972 offsets[p * (depth + 2) + d + 1] = i; 4973 break; 4974 } 4975 } 4976 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4977 } 4978 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); 4979 } 4980 for (d = 0; d < depth + 1; ++d) { 4981 PetscInt dof; 4982 4983 /* Copy in support of first point */ 4984 dof = offsets[d + 1] - offsets[d]; 4985 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4986 /* Check each successive cone */ 4987 for (p = 1; p < numPoints && joinSize; ++p) { 4988 PetscInt newJoinSize = 0; 4989 4990 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4991 for (c = 0; c < dof; ++c) { 4992 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4993 4994 for (m = 0; m < joinSize; ++m) { 4995 if (point == join[i][m]) { 4996 join[1 - i][newJoinSize++] = point; 4997 break; 4998 } 4999 } 5000 } 5001 joinSize = newJoinSize; 5002 i = 1 - i; 5003 } 5004 if (joinSize) break; 5005 } 5006 *numCoveredPoints = joinSize; 5007 *coveredPoints = join[i]; 5008 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 5009 PetscCall(PetscFree(closures)); 5010 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 5011 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 5012 PetscFunctionReturn(PETSC_SUCCESS); 5013 } 5014 5015 /*@C 5016 DMPlexGetMeet - Get an array for the meet of the set of points 5017 5018 Not Collective 5019 5020 Input Parameters: 5021 + dm - The `DMPLEX` object 5022 . numPoints - The number of input points for the meet 5023 - points - The input points, of length `numPoints` 5024 5025 Output Parameters: 5026 + numCoveringPoints - The number of points in the meet 5027 - coveringPoints - The points in the meet, of length `numCoveringPoints` 5028 5029 Level: intermediate 5030 5031 Note: 5032 Currently, this is restricted to a single level meet 5033 5034 Fortran Notes: 5035 `coveringPoints` must be declared with 5036 .vb 5037 PetscInt, pointer :: coveringPoints(:) 5038 .ve 5039 5040 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5041 5042 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5043 @*/ 5044 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 5045 { 5046 DM_Plex *mesh = (DM_Plex *)dm->data; 5047 PetscInt *meet[2]; 5048 PetscInt meetSize, i = 0; 5049 PetscInt dof, off, p, c, m; 5050 PetscInt maxConeSize; 5051 5052 PetscFunctionBegin; 5053 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5054 PetscAssertPointer(points, 3); 5055 PetscAssertPointer(numCoveringPoints, 4); 5056 PetscAssertPointer(coveringPoints, 5); 5057 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 5058 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 5059 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 5060 /* Copy in cone of first point */ 5061 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 5062 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 5063 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5064 /* Check each successive cone */ 5065 for (p = 1; p < numPoints; ++p) { 5066 PetscInt newMeetSize = 0; 5067 5068 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5069 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5070 for (c = 0; c < dof; ++c) { 5071 const PetscInt point = mesh->cones[off + c]; 5072 5073 for (m = 0; m < meetSize; ++m) { 5074 if (point == meet[i][m]) { 5075 meet[1 - i][newMeetSize++] = point; 5076 break; 5077 } 5078 } 5079 } 5080 meetSize = newMeetSize; 5081 i = 1 - i; 5082 } 5083 *numCoveringPoints = meetSize; 5084 *coveringPoints = meet[i]; 5085 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5086 PetscFunctionReturn(PETSC_SUCCESS); 5087 } 5088 5089 /*@C 5090 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5091 5092 Not Collective 5093 5094 Input Parameters: 5095 + dm - The `DMPLEX` object 5096 . numPoints - The number of input points for the meet 5097 - points - The input points 5098 5099 Output Parameters: 5100 + numCoveredPoints - The number of points in the meet 5101 - coveredPoints - The points in the meet 5102 5103 Level: intermediate 5104 5105 Fortran Notes: 5106 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5107 5108 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5109 @*/ 5110 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5111 { 5112 PetscFunctionBegin; 5113 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5114 if (points) PetscAssertPointer(points, 3); 5115 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5116 PetscAssertPointer(coveredPoints, 5); 5117 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5118 if (numCoveredPoints) *numCoveredPoints = 0; 5119 PetscFunctionReturn(PETSC_SUCCESS); 5120 } 5121 5122 /*@C 5123 DMPlexGetFullMeet - Get an array for the meet of the set of points 5124 5125 Not Collective 5126 5127 Input Parameters: 5128 + dm - The `DMPLEX` object 5129 . numPoints - The number of input points for the meet 5130 - points - The input points, of length `numPoints` 5131 5132 Output Parameters: 5133 + numCoveredPoints - The number of points in the meet 5134 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5135 5136 Level: intermediate 5137 5138 Fortran Notes: 5139 `points` and `coveredPoints` must be declared with 5140 .vb 5141 PetscInt, pointer :: points(:) 5142 PetscInt, pointer :: coveredPoints(:) 5143 .ve 5144 5145 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5146 5147 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5148 @*/ 5149 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5150 { 5151 PetscInt *offsets, **closures; 5152 PetscInt *meet[2]; 5153 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5154 PetscInt p, h, c, m, mc; 5155 5156 PetscFunctionBegin; 5157 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5158 PetscAssertPointer(points, 3); 5159 PetscAssertPointer(numCoveredPoints, 4); 5160 PetscAssertPointer(coveredPoints, 5); 5161 5162 PetscCall(DMPlexGetDepth(dm, &height)); 5163 PetscCall(PetscMalloc1(numPoints, &closures)); 5164 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5165 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5166 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5167 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5168 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5169 5170 for (p = 0; p < numPoints; ++p) { 5171 PetscInt closureSize; 5172 5173 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5174 5175 offsets[p * (height + 2) + 0] = 0; 5176 for (h = 0; h < height + 1; ++h) { 5177 PetscInt pStart, pEnd, i; 5178 5179 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5180 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5181 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5182 offsets[p * (height + 2) + h + 1] = i; 5183 break; 5184 } 5185 } 5186 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5187 } 5188 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); 5189 } 5190 for (h = 0; h < height + 1; ++h) { 5191 PetscInt dof; 5192 5193 /* Copy in cone of first point */ 5194 dof = offsets[h + 1] - offsets[h]; 5195 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5196 /* Check each successive cone */ 5197 for (p = 1; p < numPoints && meetSize; ++p) { 5198 PetscInt newMeetSize = 0; 5199 5200 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5201 for (c = 0; c < dof; ++c) { 5202 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5203 5204 for (m = 0; m < meetSize; ++m) { 5205 if (point == meet[i][m]) { 5206 meet[1 - i][newMeetSize++] = point; 5207 break; 5208 } 5209 } 5210 } 5211 meetSize = newMeetSize; 5212 i = 1 - i; 5213 } 5214 if (meetSize) break; 5215 } 5216 *numCoveredPoints = meetSize; 5217 *coveredPoints = meet[i]; 5218 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5219 PetscCall(PetscFree(closures)); 5220 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5221 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5222 PetscFunctionReturn(PETSC_SUCCESS); 5223 } 5224 5225 /*@ 5226 DMPlexEqual - Determine if two `DM` have the same topology 5227 5228 Not Collective 5229 5230 Input Parameters: 5231 + dmA - A `DMPLEX` object 5232 - dmB - A `DMPLEX` object 5233 5234 Output Parameter: 5235 . equal - `PETSC_TRUE` if the topologies are identical 5236 5237 Level: intermediate 5238 5239 Note: 5240 We are not solving graph isomorphism, so we do not permute. 5241 5242 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5243 @*/ 5244 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5245 { 5246 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5247 5248 PetscFunctionBegin; 5249 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5250 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5251 PetscAssertPointer(equal, 3); 5252 5253 *equal = PETSC_FALSE; 5254 PetscCall(DMPlexGetDepth(dmA, &depth)); 5255 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5256 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5257 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5258 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5259 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5260 for (p = pStart; p < pEnd; ++p) { 5261 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5262 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5263 5264 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5265 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5266 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5267 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5268 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5269 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5270 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5271 for (c = 0; c < coneSize; ++c) { 5272 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5273 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5274 } 5275 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5276 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5277 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5278 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5279 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5280 for (s = 0; s < supportSize; ++s) { 5281 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5282 } 5283 } 5284 *equal = PETSC_TRUE; 5285 PetscFunctionReturn(PETSC_SUCCESS); 5286 } 5287 5288 /*@ 5289 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5290 5291 Not Collective 5292 5293 Input Parameters: 5294 + dm - The `DMPLEX` 5295 . cellDim - The cell dimension 5296 - numCorners - The number of vertices on a cell 5297 5298 Output Parameter: 5299 . numFaceVertices - The number of vertices on a face 5300 5301 Level: developer 5302 5303 Note: 5304 Of course this can only work for a restricted set of symmetric shapes 5305 5306 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5307 @*/ 5308 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5309 { 5310 MPI_Comm comm; 5311 5312 PetscFunctionBegin; 5313 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5314 PetscAssertPointer(numFaceVertices, 4); 5315 switch (cellDim) { 5316 case 0: 5317 *numFaceVertices = 0; 5318 break; 5319 case 1: 5320 *numFaceVertices = 1; 5321 break; 5322 case 2: 5323 switch (numCorners) { 5324 case 3: /* triangle */ 5325 *numFaceVertices = 2; /* Edge has 2 vertices */ 5326 break; 5327 case 4: /* quadrilateral */ 5328 *numFaceVertices = 2; /* Edge has 2 vertices */ 5329 break; 5330 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5331 *numFaceVertices = 3; /* Edge has 3 vertices */ 5332 break; 5333 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5334 *numFaceVertices = 3; /* Edge has 3 vertices */ 5335 break; 5336 default: 5337 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5338 } 5339 break; 5340 case 3: 5341 switch (numCorners) { 5342 case 4: /* tetradehdron */ 5343 *numFaceVertices = 3; /* Face has 3 vertices */ 5344 break; 5345 case 6: /* tet cohesive cells */ 5346 *numFaceVertices = 4; /* Face has 4 vertices */ 5347 break; 5348 case 8: /* hexahedron */ 5349 *numFaceVertices = 4; /* Face has 4 vertices */ 5350 break; 5351 case 9: /* tet cohesive Lagrange cells */ 5352 *numFaceVertices = 6; /* Face has 6 vertices */ 5353 break; 5354 case 10: /* quadratic tetrahedron */ 5355 *numFaceVertices = 6; /* Face has 6 vertices */ 5356 break; 5357 case 12: /* hex cohesive Lagrange cells */ 5358 *numFaceVertices = 6; /* Face has 6 vertices */ 5359 break; 5360 case 18: /* quadratic tet cohesive Lagrange cells */ 5361 *numFaceVertices = 6; /* Face has 6 vertices */ 5362 break; 5363 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5364 *numFaceVertices = 9; /* Face has 9 vertices */ 5365 break; 5366 default: 5367 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5368 } 5369 break; 5370 default: 5371 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5372 } 5373 PetscFunctionReturn(PETSC_SUCCESS); 5374 } 5375 5376 /*@ 5377 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5378 5379 Not Collective 5380 5381 Input Parameter: 5382 . dm - The `DMPLEX` object 5383 5384 Output Parameter: 5385 . depthLabel - The `DMLabel` recording point depth 5386 5387 Level: developer 5388 5389 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5390 @*/ 5391 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5392 { 5393 PetscFunctionBegin; 5394 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5395 PetscAssertPointer(depthLabel, 2); 5396 *depthLabel = dm->depthLabel; 5397 PetscFunctionReturn(PETSC_SUCCESS); 5398 } 5399 5400 /*@ 5401 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5402 5403 Not Collective 5404 5405 Input Parameter: 5406 . dm - The `DMPLEX` object 5407 5408 Output Parameter: 5409 . depth - The number of strata (breadth first levels) in the DAG 5410 5411 Level: developer 5412 5413 Notes: 5414 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5415 5416 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5417 5418 An empty mesh gives -1. 5419 5420 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5421 @*/ 5422 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5423 { 5424 DM_Plex *mesh = (DM_Plex *)dm->data; 5425 DMLabel label; 5426 PetscInt d = -1; 5427 5428 PetscFunctionBegin; 5429 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5430 PetscAssertPointer(depth, 2); 5431 if (mesh->tr) { 5432 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5433 } else { 5434 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5435 // Allow missing depths 5436 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5437 *depth = d; 5438 } 5439 PetscFunctionReturn(PETSC_SUCCESS); 5440 } 5441 5442 /*@ 5443 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5444 5445 Not Collective 5446 5447 Input Parameters: 5448 + dm - The `DMPLEX` object 5449 - depth - The requested depth 5450 5451 Output Parameters: 5452 + start - The first point at this `depth` 5453 - end - One beyond the last point at this `depth` 5454 5455 Level: developer 5456 5457 Notes: 5458 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5459 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5460 higher dimension, e.g., "edges". 5461 5462 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5463 @*/ 5464 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5465 { 5466 DM_Plex *mesh = (DM_Plex *)dm->data; 5467 DMLabel label; 5468 PetscInt pStart, pEnd; 5469 5470 PetscFunctionBegin; 5471 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5472 if (start) { 5473 PetscAssertPointer(start, 3); 5474 *start = 0; 5475 } 5476 if (end) { 5477 PetscAssertPointer(end, 4); 5478 *end = 0; 5479 } 5480 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5481 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5482 if (depth < 0) { 5483 if (start) *start = pStart; 5484 if (end) *end = pEnd; 5485 PetscFunctionReturn(PETSC_SUCCESS); 5486 } 5487 if (mesh->tr) { 5488 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5489 } else { 5490 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5491 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5492 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5493 } 5494 PetscFunctionReturn(PETSC_SUCCESS); 5495 } 5496 5497 /*@ 5498 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5499 5500 Not Collective 5501 5502 Input Parameters: 5503 + dm - The `DMPLEX` object 5504 - height - The requested height 5505 5506 Output Parameters: 5507 + start - The first point at this `height` 5508 - end - One beyond the last point at this `height` 5509 5510 Level: developer 5511 5512 Notes: 5513 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5514 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5515 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5516 5517 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5518 @*/ 5519 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5520 { 5521 DMLabel label; 5522 PetscInt depth, pStart, pEnd; 5523 5524 PetscFunctionBegin; 5525 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5526 if (start) { 5527 PetscAssertPointer(start, 3); 5528 *start = 0; 5529 } 5530 if (end) { 5531 PetscAssertPointer(end, 4); 5532 *end = 0; 5533 } 5534 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5535 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5536 if (height < 0) { 5537 if (start) *start = pStart; 5538 if (end) *end = pEnd; 5539 PetscFunctionReturn(PETSC_SUCCESS); 5540 } 5541 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5542 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5543 else PetscCall(DMGetDimension(dm, &depth)); 5544 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5545 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5546 PetscFunctionReturn(PETSC_SUCCESS); 5547 } 5548 5549 /*@ 5550 DMPlexGetPointDepth - Get the `depth` of a given point 5551 5552 Not Collective 5553 5554 Input Parameters: 5555 + dm - The `DMPLEX` object 5556 - point - The point 5557 5558 Output Parameter: 5559 . depth - The depth of the `point` 5560 5561 Level: intermediate 5562 5563 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5564 @*/ 5565 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5566 { 5567 PetscFunctionBegin; 5568 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5569 PetscAssertPointer(depth, 3); 5570 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5571 PetscFunctionReturn(PETSC_SUCCESS); 5572 } 5573 5574 /*@ 5575 DMPlexGetPointHeight - Get the `height` of a given point 5576 5577 Not Collective 5578 5579 Input Parameters: 5580 + dm - The `DMPLEX` object 5581 - point - The point 5582 5583 Output Parameter: 5584 . height - The height of the `point` 5585 5586 Level: intermediate 5587 5588 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5589 @*/ 5590 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5591 { 5592 PetscInt n, pDepth; 5593 5594 PetscFunctionBegin; 5595 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5596 PetscAssertPointer(height, 3); 5597 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5598 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5599 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5600 PetscFunctionReturn(PETSC_SUCCESS); 5601 } 5602 5603 /*@ 5604 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5605 5606 Not Collective 5607 5608 Input Parameter: 5609 . dm - The `DMPLEX` object 5610 5611 Output Parameter: 5612 . celltypeLabel - The `DMLabel` recording cell polytope type 5613 5614 Level: developer 5615 5616 Note: 5617 This function will trigger automatica computation of cell types. This can be disabled by calling 5618 `DMCreateLabel`(dm, "celltype") beforehand. 5619 5620 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5621 @*/ 5622 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5623 { 5624 PetscFunctionBegin; 5625 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5626 PetscAssertPointer(celltypeLabel, 2); 5627 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5628 *celltypeLabel = dm->celltypeLabel; 5629 PetscFunctionReturn(PETSC_SUCCESS); 5630 } 5631 5632 /*@ 5633 DMPlexGetCellType - Get the polytope type of a given cell 5634 5635 Not Collective 5636 5637 Input Parameters: 5638 + dm - The `DMPLEX` object 5639 - cell - The cell 5640 5641 Output Parameter: 5642 . celltype - The polytope type of the cell 5643 5644 Level: intermediate 5645 5646 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5647 @*/ 5648 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5649 { 5650 DM_Plex *mesh = (DM_Plex *)dm->data; 5651 DMLabel label; 5652 PetscInt ct; 5653 5654 PetscFunctionBegin; 5655 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5656 PetscAssertPointer(celltype, 3); 5657 if (mesh->tr) { 5658 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5659 } else { 5660 PetscInt pStart, pEnd; 5661 5662 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5663 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5664 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5665 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5666 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5667 for (PetscInt p = pStart; p < pEnd; p++) { 5668 PetscCall(DMLabelGetValue(label, p, &ct)); 5669 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5670 } 5671 } 5672 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5673 if (PetscDefined(USE_DEBUG)) { 5674 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5675 PetscCall(DMLabelGetValue(label, cell, &ct)); 5676 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5677 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5678 } 5679 } 5680 PetscFunctionReturn(PETSC_SUCCESS); 5681 } 5682 5683 /*@ 5684 DMPlexSetCellType - Set the polytope type of a given cell 5685 5686 Not Collective 5687 5688 Input Parameters: 5689 + dm - The `DMPLEX` object 5690 . cell - The cell 5691 - celltype - The polytope type of the cell 5692 5693 Level: advanced 5694 5695 Note: 5696 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5697 is executed. This function will override the computed type. However, if automatic classification will not succeed 5698 and a user wants to manually specify all types, the classification must be disabled by calling 5699 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5700 5701 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5702 @*/ 5703 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5704 { 5705 DM_Plex *mesh = (DM_Plex *)dm->data; 5706 DMLabel label; 5707 PetscInt pStart, pEnd; 5708 5709 PetscFunctionBegin; 5710 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5711 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5712 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5713 PetscCall(DMLabelSetValue(label, cell, celltype)); 5714 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5715 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5716 PetscFunctionReturn(PETSC_SUCCESS); 5717 } 5718 5719 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5720 { 5721 PetscSection section; 5722 PetscInt maxHeight; 5723 const char *prefix; 5724 5725 PetscFunctionBegin; 5726 PetscCall(DMClone(dm, cdm)); 5727 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5728 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5729 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5730 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5731 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5732 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5733 PetscCall(DMSetLocalSection(*cdm, section)); 5734 PetscCall(PetscSectionDestroy(§ion)); 5735 5736 PetscCall(DMSetNumFields(*cdm, 1)); 5737 PetscCall(DMCreateDS(*cdm)); 5738 (*cdm)->cloneOpts = PETSC_TRUE; 5739 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5740 PetscFunctionReturn(PETSC_SUCCESS); 5741 } 5742 5743 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5744 { 5745 Vec coordsLocal, cellCoordsLocal; 5746 DM coordsDM, cellCoordsDM; 5747 5748 PetscFunctionBegin; 5749 *field = NULL; 5750 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5751 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5752 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5753 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5754 if (coordsLocal && coordsDM) { 5755 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5756 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5757 } 5758 PetscFunctionReturn(PETSC_SUCCESS); 5759 } 5760 5761 /*@ 5762 DMPlexGetConeSection - Return a section which describes the layout of cone data 5763 5764 Not Collective 5765 5766 Input Parameter: 5767 . dm - The `DMPLEX` object 5768 5769 Output Parameter: 5770 . section - The `PetscSection` object 5771 5772 Level: developer 5773 5774 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5775 @*/ 5776 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5777 { 5778 DM_Plex *mesh = (DM_Plex *)dm->data; 5779 5780 PetscFunctionBegin; 5781 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5782 if (section) *section = mesh->coneSection; 5783 PetscFunctionReturn(PETSC_SUCCESS); 5784 } 5785 5786 /*@ 5787 DMPlexGetSupportSection - Return a section which describes the layout of support data 5788 5789 Not Collective 5790 5791 Input Parameter: 5792 . dm - The `DMPLEX` object 5793 5794 Output Parameter: 5795 . section - The `PetscSection` object 5796 5797 Level: developer 5798 5799 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5800 @*/ 5801 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5802 { 5803 DM_Plex *mesh = (DM_Plex *)dm->data; 5804 5805 PetscFunctionBegin; 5806 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5807 if (section) *section = mesh->supportSection; 5808 PetscFunctionReturn(PETSC_SUCCESS); 5809 } 5810 5811 /*@C 5812 DMPlexGetCones - Return cone data 5813 5814 Not Collective 5815 5816 Input Parameter: 5817 . dm - The `DMPLEX` object 5818 5819 Output Parameter: 5820 . cones - The cone for each point 5821 5822 Level: developer 5823 5824 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5825 @*/ 5826 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5827 { 5828 DM_Plex *mesh = (DM_Plex *)dm->data; 5829 5830 PetscFunctionBegin; 5831 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5832 if (cones) *cones = mesh->cones; 5833 PetscFunctionReturn(PETSC_SUCCESS); 5834 } 5835 5836 /*@C 5837 DMPlexGetConeOrientations - Return cone orientation data 5838 5839 Not Collective 5840 5841 Input Parameter: 5842 . dm - The `DMPLEX` object 5843 5844 Output Parameter: 5845 . coneOrientations - The array of cone orientations for all points 5846 5847 Level: developer 5848 5849 Notes: 5850 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5851 as returned by `DMPlexGetConeOrientation()`. 5852 5853 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5854 5855 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5856 @*/ 5857 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5858 { 5859 DM_Plex *mesh = (DM_Plex *)dm->data; 5860 5861 PetscFunctionBegin; 5862 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5863 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5864 PetscFunctionReturn(PETSC_SUCCESS); 5865 } 5866 5867 /* FEM Support */ 5868 5869 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5870 { 5871 PetscInt depth; 5872 5873 PetscFunctionBegin; 5874 PetscCall(DMPlexGetDepth(plex, &depth)); 5875 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5876 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5877 PetscFunctionReturn(PETSC_SUCCESS); 5878 } 5879 5880 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5881 { 5882 PetscInt depth; 5883 5884 PetscFunctionBegin; 5885 PetscCall(DMPlexGetDepth(plex, &depth)); 5886 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5887 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5888 PetscFunctionReturn(PETSC_SUCCESS); 5889 } 5890 5891 /* 5892 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5893 representing a line in the section. 5894 */ 5895 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5896 { 5897 PetscObject obj; 5898 PetscClassId id; 5899 PetscFE fe = NULL; 5900 5901 PetscFunctionBeginHot; 5902 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5903 PetscCall(DMGetField(dm, field, NULL, &obj)); 5904 PetscCall(PetscObjectGetClassId(obj, &id)); 5905 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5906 5907 if (!fe) { 5908 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5909 /* An order k SEM disc has k-1 dofs on an edge */ 5910 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5911 *k = *k / *Nc + 1; 5912 } else { 5913 PetscInt dual_space_size, dim; 5914 PetscDualSpace dsp; 5915 5916 PetscCall(DMGetDimension(dm, &dim)); 5917 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5918 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5919 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5920 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5921 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5922 } 5923 PetscFunctionReturn(PETSC_SUCCESS); 5924 } 5925 5926 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5927 { 5928 PetscFunctionBeginHot; 5929 if (tensor) { 5930 *dof = PetscPowInt(k + 1, dim); 5931 } else { 5932 switch (dim) { 5933 case 1: 5934 *dof = k + 1; 5935 break; 5936 case 2: 5937 *dof = ((k + 1) * (k + 2)) / 2; 5938 break; 5939 case 3: 5940 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5941 break; 5942 default: 5943 *dof = 0; 5944 } 5945 } 5946 PetscFunctionReturn(PETSC_SUCCESS); 5947 } 5948 5949 /*@ 5950 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5951 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5952 section provided (or the section of the `DM`). 5953 5954 Input Parameters: 5955 + dm - The `DM` 5956 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5957 - section - The `PetscSection` to reorder, or `NULL` for the default section 5958 5959 Example: 5960 A typical interpolated single-quad mesh might order points as 5961 .vb 5962 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5963 5964 v4 -- e6 -- v3 5965 | | 5966 e7 c0 e8 5967 | | 5968 v1 -- e5 -- v2 5969 .ve 5970 5971 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5972 dofs in the order of points, e.g., 5973 .vb 5974 c0 -> [0,1,2,3] 5975 v1 -> [4] 5976 ... 5977 e5 -> [8, 9] 5978 .ve 5979 5980 which corresponds to the dofs 5981 .vb 5982 6 10 11 7 5983 13 2 3 15 5984 12 0 1 14 5985 4 8 9 5 5986 .ve 5987 5988 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5989 .vb 5990 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5991 .ve 5992 5993 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5994 .vb 5995 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5996 .ve 5997 5998 Level: developer 5999 6000 Notes: 6001 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 6002 degree of the basis. 6003 6004 This is required to run with libCEED. 6005 6006 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 6007 @*/ 6008 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 6009 { 6010 DMLabel label; 6011 PetscInt dim, depth = -1, eStart = -1, Nf; 6012 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 6013 6014 PetscFunctionBegin; 6015 PetscCall(DMGetDimension(dm, &dim)); 6016 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 6017 if (point < 0) { 6018 PetscInt sStart, sEnd; 6019 6020 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6021 point = sEnd - sStart ? sStart : point; 6022 } 6023 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6024 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6025 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6026 if (depth == 1) { 6027 eStart = point; 6028 } else if (depth == dim) { 6029 const PetscInt *cone; 6030 6031 PetscCall(DMPlexGetCone(dm, point, &cone)); 6032 if (dim == 2) eStart = cone[0]; 6033 else if (dim == 3) { 6034 const PetscInt *cone2; 6035 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6036 eStart = cone2[0]; 6037 } 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); 6038 } 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); 6039 6040 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6041 for (PetscInt d = 1; d <= dim; d++) { 6042 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6043 PetscInt *perm; 6044 6045 for (f = 0; f < Nf; ++f) { 6046 PetscInt dof; 6047 6048 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6049 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6050 if (!continuous && d < dim) continue; 6051 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6052 size += dof * Nc; 6053 } 6054 PetscCall(PetscMalloc1(size, &perm)); 6055 for (f = 0; f < Nf; ++f) { 6056 switch (d) { 6057 case 1: 6058 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6059 if (!continuous && d < dim) continue; 6060 /* 6061 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6062 We want [ vtx0; edge of length k-1; vtx1 ] 6063 */ 6064 if (continuous) { 6065 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6066 for (i = 0; i < k - 1; i++) 6067 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6068 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6069 foffset = offset; 6070 } else { 6071 PetscInt dof; 6072 6073 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6074 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6075 foffset = offset; 6076 } 6077 break; 6078 case 2: 6079 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6080 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6081 if (!continuous && d < dim) continue; 6082 /* The SEM order is 6083 6084 v_lb, {e_b}, v_rb, 6085 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6086 v_lt, reverse {e_t}, v_rt 6087 */ 6088 if (continuous) { 6089 const PetscInt of = 0; 6090 const PetscInt oeb = of + PetscSqr(k - 1); 6091 const PetscInt oer = oeb + (k - 1); 6092 const PetscInt oet = oer + (k - 1); 6093 const PetscInt oel = oet + (k - 1); 6094 const PetscInt ovlb = oel + (k - 1); 6095 const PetscInt ovrb = ovlb + 1; 6096 const PetscInt ovrt = ovrb + 1; 6097 const PetscInt ovlt = ovrt + 1; 6098 PetscInt o; 6099 6100 /* bottom */ 6101 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6102 for (o = oeb; o < oer; ++o) 6103 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6104 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6105 /* middle */ 6106 for (i = 0; i < k - 1; ++i) { 6107 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6108 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6109 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6110 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6111 } 6112 /* top */ 6113 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6114 for (o = oel - 1; o >= oet; --o) 6115 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6116 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6117 foffset = offset; 6118 } else { 6119 PetscInt dof; 6120 6121 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6122 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6123 foffset = offset; 6124 } 6125 break; 6126 case 3: 6127 /* The original hex closure is 6128 6129 {c, 6130 f_b, f_t, f_f, f_b, f_r, f_l, 6131 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6132 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6133 */ 6134 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6135 if (!continuous && d < dim) continue; 6136 /* The SEM order is 6137 Bottom Slice 6138 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6139 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6140 v_blb, {e_bb}, v_brb, 6141 6142 Middle Slice (j) 6143 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6144 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6145 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6146 6147 Top Slice 6148 v_tlf, {e_tf}, v_trf, 6149 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6150 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6151 */ 6152 if (continuous) { 6153 const PetscInt oc = 0; 6154 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6155 const PetscInt oft = ofb + PetscSqr(k - 1); 6156 const PetscInt off = oft + PetscSqr(k - 1); 6157 const PetscInt ofk = off + PetscSqr(k - 1); 6158 const PetscInt ofr = ofk + PetscSqr(k - 1); 6159 const PetscInt ofl = ofr + PetscSqr(k - 1); 6160 const PetscInt oebl = ofl + PetscSqr(k - 1); 6161 const PetscInt oebb = oebl + (k - 1); 6162 const PetscInt oebr = oebb + (k - 1); 6163 const PetscInt oebf = oebr + (k - 1); 6164 const PetscInt oetf = oebf + (k - 1); 6165 const PetscInt oetr = oetf + (k - 1); 6166 const PetscInt oetb = oetr + (k - 1); 6167 const PetscInt oetl = oetb + (k - 1); 6168 const PetscInt oerf = oetl + (k - 1); 6169 const PetscInt oelf = oerf + (k - 1); 6170 const PetscInt oelb = oelf + (k - 1); 6171 const PetscInt oerb = oelb + (k - 1); 6172 const PetscInt ovblf = oerb + (k - 1); 6173 const PetscInt ovblb = ovblf + 1; 6174 const PetscInt ovbrb = ovblb + 1; 6175 const PetscInt ovbrf = ovbrb + 1; 6176 const PetscInt ovtlf = ovbrf + 1; 6177 const PetscInt ovtrf = ovtlf + 1; 6178 const PetscInt ovtrb = ovtrf + 1; 6179 const PetscInt ovtlb = ovtrb + 1; 6180 PetscInt o, n; 6181 6182 /* Bottom Slice */ 6183 /* bottom */ 6184 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6185 for (o = oetf - 1; o >= oebf; --o) 6186 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6187 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6188 /* middle */ 6189 for (i = 0; i < k - 1; ++i) { 6190 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6191 for (n = 0; n < k - 1; ++n) { 6192 o = ofb + n * (k - 1) + i; 6193 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6194 } 6195 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6196 } 6197 /* top */ 6198 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6199 for (o = oebb; o < oebr; ++o) 6200 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6201 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6202 6203 /* Middle Slice */ 6204 for (j = 0; j < k - 1; ++j) { 6205 /* bottom */ 6206 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6207 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6208 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6209 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6210 /* middle */ 6211 for (i = 0; i < k - 1; ++i) { 6212 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6213 for (n = 0; n < k - 1; ++n) 6214 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6215 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6216 } 6217 /* top */ 6218 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6219 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6220 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6221 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6222 } 6223 6224 /* Top Slice */ 6225 /* bottom */ 6226 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6227 for (o = oetf; o < oetr; ++o) 6228 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6229 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6230 /* middle */ 6231 for (i = 0; i < k - 1; ++i) { 6232 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6233 for (n = 0; n < k - 1; ++n) 6234 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6235 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6236 } 6237 /* top */ 6238 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6239 for (o = oetl - 1; o >= oetb; --o) 6240 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6241 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6242 6243 foffset = offset; 6244 } else { 6245 PetscInt dof; 6246 6247 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6248 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6249 foffset = offset; 6250 } 6251 break; 6252 default: 6253 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6254 } 6255 } 6256 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6257 /* Check permutation */ 6258 { 6259 PetscInt *check; 6260 6261 PetscCall(PetscMalloc1(size, &check)); 6262 for (i = 0; i < size; ++i) { 6263 check[i] = -1; 6264 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6265 } 6266 for (i = 0; i < size; ++i) check[perm[i]] = i; 6267 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6268 PetscCall(PetscFree(check)); 6269 } 6270 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6271 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6272 PetscInt *loc_perm; 6273 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6274 for (PetscInt i = 0; i < size; i++) { 6275 loc_perm[i] = perm[i]; 6276 loc_perm[size + i] = size + perm[i]; 6277 } 6278 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6279 } 6280 } 6281 PetscFunctionReturn(PETSC_SUCCESS); 6282 } 6283 6284 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6285 { 6286 PetscDS prob; 6287 PetscInt depth, Nf, h; 6288 DMLabel label; 6289 6290 PetscFunctionBeginHot; 6291 PetscCall(DMGetDS(dm, &prob)); 6292 Nf = prob->Nf; 6293 label = dm->depthLabel; 6294 *dspace = NULL; 6295 if (field < Nf) { 6296 PetscObject disc = prob->disc[field]; 6297 6298 if (disc->classid == PETSCFE_CLASSID) { 6299 PetscDualSpace dsp; 6300 6301 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6302 PetscCall(DMLabelGetNumValues(label, &depth)); 6303 PetscCall(DMLabelGetValue(label, point, &h)); 6304 h = depth - 1 - h; 6305 if (h) { 6306 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6307 } else { 6308 *dspace = dsp; 6309 } 6310 } 6311 } 6312 PetscFunctionReturn(PETSC_SUCCESS); 6313 } 6314 6315 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6316 { 6317 PetscScalar *array; 6318 const PetscScalar *vArray; 6319 const PetscInt *cone, *coneO; 6320 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6321 6322 PetscFunctionBeginHot; 6323 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6324 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6325 PetscCall(DMPlexGetCone(dm, point, &cone)); 6326 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6327 if (!values || !*values) { 6328 if ((point >= pStart) && (point < pEnd)) { 6329 PetscInt dof; 6330 6331 PetscCall(PetscSectionGetDof(section, point, &dof)); 6332 size += dof; 6333 } 6334 for (p = 0; p < numPoints; ++p) { 6335 const PetscInt cp = cone[p]; 6336 PetscInt dof; 6337 6338 if ((cp < pStart) || (cp >= pEnd)) continue; 6339 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6340 size += dof; 6341 } 6342 if (!values) { 6343 if (csize) *csize = size; 6344 PetscFunctionReturn(PETSC_SUCCESS); 6345 } 6346 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6347 } else { 6348 array = *values; 6349 } 6350 size = 0; 6351 PetscCall(VecGetArrayRead(v, &vArray)); 6352 if ((point >= pStart) && (point < pEnd)) { 6353 PetscInt dof, off, d; 6354 const PetscScalar *varr; 6355 6356 PetscCall(PetscSectionGetDof(section, point, &dof)); 6357 PetscCall(PetscSectionGetOffset(section, point, &off)); 6358 varr = PetscSafePointerPlusOffset(vArray, off); 6359 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6360 size += dof; 6361 } 6362 for (p = 0; p < numPoints; ++p) { 6363 const PetscInt cp = cone[p]; 6364 PetscInt o = coneO[p]; 6365 PetscInt dof, off, d; 6366 const PetscScalar *varr; 6367 6368 if ((cp < pStart) || (cp >= pEnd)) continue; 6369 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6370 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6371 varr = PetscSafePointerPlusOffset(vArray, off); 6372 if (o >= 0) { 6373 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6374 } else { 6375 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6376 } 6377 size += dof; 6378 } 6379 PetscCall(VecRestoreArrayRead(v, &vArray)); 6380 if (!*values) { 6381 if (csize) *csize = size; 6382 *values = array; 6383 } else { 6384 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6385 *csize = size; 6386 } 6387 PetscFunctionReturn(PETSC_SUCCESS); 6388 } 6389 6390 /* Compress out points not in the section */ 6391 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6392 { 6393 const PetscInt np = *numPoints; 6394 PetscInt pStart, pEnd, p, q; 6395 6396 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6397 for (p = 0, q = 0; p < np; ++p) { 6398 const PetscInt r = points[p * 2]; 6399 if ((r >= pStart) && (r < pEnd)) { 6400 points[q * 2] = r; 6401 points[q * 2 + 1] = points[p * 2 + 1]; 6402 ++q; 6403 } 6404 } 6405 *numPoints = q; 6406 return PETSC_SUCCESS; 6407 } 6408 6409 /* Compressed closure does not apply closure permutation */ 6410 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6411 { 6412 const PetscInt *cla = NULL; 6413 PetscInt np, *pts = NULL; 6414 6415 PetscFunctionBeginHot; 6416 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6417 if (!ornt && *clPoints) { 6418 PetscInt dof, off; 6419 6420 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6421 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6422 PetscCall(ISGetIndices(*clPoints, &cla)); 6423 np = dof / 2; 6424 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6425 } else { 6426 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6427 PetscCall(CompressPoints_Private(section, &np, pts)); 6428 } 6429 *numPoints = np; 6430 *points = pts; 6431 *clp = cla; 6432 PetscFunctionReturn(PETSC_SUCCESS); 6433 } 6434 6435 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6436 { 6437 PetscFunctionBeginHot; 6438 if (!*clPoints) { 6439 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6440 } else { 6441 PetscCall(ISRestoreIndices(*clPoints, clp)); 6442 } 6443 *numPoints = 0; 6444 *points = NULL; 6445 *clSec = NULL; 6446 *clPoints = NULL; 6447 *clp = NULL; 6448 PetscFunctionReturn(PETSC_SUCCESS); 6449 } 6450 6451 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6452 { 6453 PetscInt offset = 0, p; 6454 const PetscInt **perms = NULL; 6455 const PetscScalar **flips = NULL; 6456 6457 PetscFunctionBeginHot; 6458 *size = 0; 6459 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6460 for (p = 0; p < numPoints; p++) { 6461 const PetscInt point = points[2 * p]; 6462 const PetscInt *perm = perms ? perms[p] : NULL; 6463 const PetscScalar *flip = flips ? flips[p] : NULL; 6464 PetscInt dof, off, d; 6465 const PetscScalar *varr; 6466 6467 PetscCall(PetscSectionGetDof(section, point, &dof)); 6468 PetscCall(PetscSectionGetOffset(section, point, &off)); 6469 varr = PetscSafePointerPlusOffset(vArray, off); 6470 if (clperm) { 6471 if (perm) { 6472 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6473 } else { 6474 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6475 } 6476 if (flip) { 6477 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6478 } 6479 } else { 6480 if (perm) { 6481 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6482 } else { 6483 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6484 } 6485 if (flip) { 6486 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6487 } 6488 } 6489 offset += dof; 6490 } 6491 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6492 *size = offset; 6493 PetscFunctionReturn(PETSC_SUCCESS); 6494 } 6495 6496 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[]) 6497 { 6498 PetscInt offset = 0, f; 6499 6500 PetscFunctionBeginHot; 6501 *size = 0; 6502 for (f = 0; f < numFields; ++f) { 6503 PetscInt p; 6504 const PetscInt **perms = NULL; 6505 const PetscScalar **flips = NULL; 6506 6507 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6508 for (p = 0; p < numPoints; p++) { 6509 const PetscInt point = points[2 * p]; 6510 PetscInt fdof, foff, b; 6511 const PetscScalar *varr; 6512 const PetscInt *perm = perms ? perms[p] : NULL; 6513 const PetscScalar *flip = flips ? flips[p] : NULL; 6514 6515 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6516 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6517 varr = &vArray[foff]; 6518 if (clperm) { 6519 if (perm) { 6520 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6521 } else { 6522 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6523 } 6524 if (flip) { 6525 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6526 } 6527 } else { 6528 if (perm) { 6529 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6530 } else { 6531 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6532 } 6533 if (flip) { 6534 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6535 } 6536 } 6537 offset += fdof; 6538 } 6539 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6540 } 6541 *size = offset; 6542 PetscFunctionReturn(PETSC_SUCCESS); 6543 } 6544 6545 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6546 { 6547 PetscSection clSection; 6548 IS clPoints; 6549 PetscInt *points = NULL; 6550 const PetscInt *clp, *perm = NULL; 6551 PetscInt depth, numFields, numPoints, asize; 6552 6553 PetscFunctionBeginHot; 6554 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6555 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6556 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6557 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6558 PetscCall(DMPlexGetDepth(dm, &depth)); 6559 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6560 if (depth == 1 && numFields < 2) { 6561 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6562 PetscFunctionReturn(PETSC_SUCCESS); 6563 } 6564 /* Get points */ 6565 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6566 /* Get sizes */ 6567 asize = 0; 6568 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6569 PetscInt dof; 6570 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6571 asize += dof; 6572 } 6573 if (values) { 6574 const PetscScalar *vArray; 6575 PetscInt size; 6576 6577 if (*values) { 6578 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); 6579 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6580 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6581 PetscCall(VecGetArrayRead(v, &vArray)); 6582 /* Get values */ 6583 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6584 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6585 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6586 /* Cleanup array */ 6587 PetscCall(VecRestoreArrayRead(v, &vArray)); 6588 } 6589 if (csize) *csize = asize; 6590 /* Cleanup points */ 6591 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6592 PetscFunctionReturn(PETSC_SUCCESS); 6593 } 6594 6595 /*@C 6596 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6597 6598 Not collective 6599 6600 Input Parameters: 6601 + dm - The `DM` 6602 . section - The section describing the layout in `v`, or `NULL` to use the default section 6603 . v - The local vector 6604 - point - The point in the `DM` 6605 6606 Input/Output Parameters: 6607 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6608 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6609 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6610 6611 Level: intermediate 6612 6613 Notes: 6614 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6615 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6616 assembly function, and a user may already have allocated storage for this operation. 6617 6618 A typical use could be 6619 .vb 6620 values = NULL; 6621 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6622 for (cl = 0; cl < clSize; ++cl) { 6623 <Compute on closure> 6624 } 6625 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6626 .ve 6627 or 6628 .vb 6629 PetscMalloc1(clMaxSize, &values); 6630 for (p = pStart; p < pEnd; ++p) { 6631 clSize = clMaxSize; 6632 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6633 for (cl = 0; cl < clSize; ++cl) { 6634 <Compute on closure> 6635 } 6636 } 6637 PetscFree(values); 6638 .ve 6639 6640 Fortran Notes: 6641 The `csize` argument is not present in the Fortran binding. 6642 6643 `values` must be declared with 6644 .vb 6645 PetscScalar,dimension(:),pointer :: values 6646 .ve 6647 and it will be allocated internally by PETSc to hold the values returned 6648 6649 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6650 @*/ 6651 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6652 { 6653 PetscFunctionBeginHot; 6654 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6655 PetscFunctionReturn(PETSC_SUCCESS); 6656 } 6657 6658 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6659 { 6660 DMLabel depthLabel; 6661 PetscSection clSection; 6662 IS clPoints; 6663 PetscScalar *array; 6664 const PetscScalar *vArray; 6665 PetscInt *points = NULL; 6666 const PetscInt *clp, *perm = NULL; 6667 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6668 6669 PetscFunctionBeginHot; 6670 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6671 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6672 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6673 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6674 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6675 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6676 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6677 if (mdepth == 1 && numFields < 2) { 6678 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6679 PetscFunctionReturn(PETSC_SUCCESS); 6680 } 6681 /* Get points */ 6682 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6683 for (clsize = 0, p = 0; p < Np; p++) { 6684 PetscInt dof; 6685 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6686 clsize += dof; 6687 } 6688 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6689 /* Filter points */ 6690 for (p = 0; p < numPoints * 2; p += 2) { 6691 PetscInt dep; 6692 6693 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6694 if (dep != depth) continue; 6695 points[Np * 2 + 0] = points[p]; 6696 points[Np * 2 + 1] = points[p + 1]; 6697 ++Np; 6698 } 6699 /* Get array */ 6700 if (!values || !*values) { 6701 PetscInt asize = 0, dof; 6702 6703 for (p = 0; p < Np * 2; p += 2) { 6704 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6705 asize += dof; 6706 } 6707 if (!values) { 6708 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6709 if (csize) *csize = asize; 6710 PetscFunctionReturn(PETSC_SUCCESS); 6711 } 6712 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6713 } else { 6714 array = *values; 6715 } 6716 PetscCall(VecGetArrayRead(v, &vArray)); 6717 /* Get values */ 6718 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6719 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6720 /* Cleanup points */ 6721 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6722 /* Cleanup array */ 6723 PetscCall(VecRestoreArrayRead(v, &vArray)); 6724 if (!*values) { 6725 if (csize) *csize = size; 6726 *values = array; 6727 } else { 6728 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6729 *csize = size; 6730 } 6731 PetscFunctionReturn(PETSC_SUCCESS); 6732 } 6733 6734 /*@C 6735 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6736 6737 Not collective 6738 6739 Input Parameters: 6740 + dm - The `DM` 6741 . section - The section describing the layout in `v`, or `NULL` to use the default section 6742 . v - The local vector 6743 . point - The point in the `DM` 6744 . csize - The number of values in the closure, or `NULL` 6745 - values - The array of values 6746 6747 Level: intermediate 6748 6749 Note: 6750 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6751 6752 Fortran Note: 6753 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6754 6755 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6756 @*/ 6757 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6758 { 6759 PetscInt size = 0; 6760 6761 PetscFunctionBegin; 6762 /* Should work without recalculating size */ 6763 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6764 *values = NULL; 6765 PetscFunctionReturn(PETSC_SUCCESS); 6766 } 6767 6768 static inline void add(PetscScalar *x, PetscScalar y) 6769 { 6770 *x += y; 6771 } 6772 static inline void insert(PetscScalar *x, PetscScalar y) 6773 { 6774 *x = y; 6775 } 6776 6777 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[]) 6778 { 6779 PetscInt cdof; /* The number of constraints on this point */ 6780 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6781 PetscScalar *a; 6782 PetscInt off, cind = 0, k; 6783 6784 PetscFunctionBegin; 6785 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6786 PetscCall(PetscSectionGetOffset(section, point, &off)); 6787 a = &array[off]; 6788 if (!cdof || setBC) { 6789 if (clperm) { 6790 if (perm) { 6791 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6792 } else { 6793 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6794 } 6795 } else { 6796 if (perm) { 6797 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6798 } else { 6799 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6800 } 6801 } 6802 } else { 6803 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6804 if (clperm) { 6805 if (perm) { 6806 for (k = 0; k < dof; ++k) { 6807 if ((cind < cdof) && (k == cdofs[cind])) { 6808 ++cind; 6809 continue; 6810 } 6811 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6812 } 6813 } else { 6814 for (k = 0; k < dof; ++k) { 6815 if ((cind < cdof) && (k == cdofs[cind])) { 6816 ++cind; 6817 continue; 6818 } 6819 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6820 } 6821 } 6822 } else { 6823 if (perm) { 6824 for (k = 0; k < dof; ++k) { 6825 if ((cind < cdof) && (k == cdofs[cind])) { 6826 ++cind; 6827 continue; 6828 } 6829 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6830 } 6831 } else { 6832 for (k = 0; k < dof; ++k) { 6833 if ((cind < cdof) && (k == cdofs[cind])) { 6834 ++cind; 6835 continue; 6836 } 6837 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6838 } 6839 } 6840 } 6841 } 6842 PetscFunctionReturn(PETSC_SUCCESS); 6843 } 6844 6845 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[]) 6846 { 6847 PetscInt cdof; /* The number of constraints on this point */ 6848 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6849 PetscScalar *a; 6850 PetscInt off, cind = 0, k; 6851 6852 PetscFunctionBegin; 6853 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6854 PetscCall(PetscSectionGetOffset(section, point, &off)); 6855 a = &array[off]; 6856 if (cdof) { 6857 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6858 if (clperm) { 6859 if (perm) { 6860 for (k = 0; k < dof; ++k) { 6861 if ((cind < cdof) && (k == cdofs[cind])) { 6862 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6863 cind++; 6864 } 6865 } 6866 } else { 6867 for (k = 0; k < dof; ++k) { 6868 if ((cind < cdof) && (k == cdofs[cind])) { 6869 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6870 cind++; 6871 } 6872 } 6873 } 6874 } else { 6875 if (perm) { 6876 for (k = 0; k < dof; ++k) { 6877 if ((cind < cdof) && (k == cdofs[cind])) { 6878 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6879 cind++; 6880 } 6881 } 6882 } else { 6883 for (k = 0; k < dof; ++k) { 6884 if ((cind < cdof) && (k == cdofs[cind])) { 6885 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6886 cind++; 6887 } 6888 } 6889 } 6890 } 6891 } 6892 PetscFunctionReturn(PETSC_SUCCESS); 6893 } 6894 6895 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[]) 6896 { 6897 PetscScalar *a; 6898 PetscInt fdof, foff, fcdof, foffset = *offset; 6899 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6900 PetscInt cind = 0, b; 6901 6902 PetscFunctionBegin; 6903 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6904 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6905 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6906 a = &array[foff]; 6907 if (!fcdof || setBC) { 6908 if (clperm) { 6909 if (perm) { 6910 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6911 } else { 6912 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6913 } 6914 } else { 6915 if (perm) { 6916 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6917 } else { 6918 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6919 } 6920 } 6921 } else { 6922 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6923 if (clperm) { 6924 if (perm) { 6925 for (b = 0; b < fdof; b++) { 6926 if ((cind < fcdof) && (b == fcdofs[cind])) { 6927 ++cind; 6928 continue; 6929 } 6930 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6931 } 6932 } else { 6933 for (b = 0; b < fdof; b++) { 6934 if ((cind < fcdof) && (b == fcdofs[cind])) { 6935 ++cind; 6936 continue; 6937 } 6938 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6939 } 6940 } 6941 } else { 6942 if (perm) { 6943 for (b = 0; b < fdof; b++) { 6944 if ((cind < fcdof) && (b == fcdofs[cind])) { 6945 ++cind; 6946 continue; 6947 } 6948 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6949 } 6950 } else { 6951 for (b = 0; b < fdof; b++) { 6952 if ((cind < fcdof) && (b == fcdofs[cind])) { 6953 ++cind; 6954 continue; 6955 } 6956 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6957 } 6958 } 6959 } 6960 } 6961 *offset += fdof; 6962 PetscFunctionReturn(PETSC_SUCCESS); 6963 } 6964 6965 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[]) 6966 { 6967 PetscScalar *a; 6968 PetscInt fdof, foff, fcdof, foffset = *offset; 6969 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6970 PetscInt Nc, cind = 0, ncind = 0, b; 6971 PetscBool ncSet, fcSet; 6972 6973 PetscFunctionBegin; 6974 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6975 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6976 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6977 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6978 a = &array[foff]; 6979 if (fcdof) { 6980 /* We just override fcdof and fcdofs with Ncc and comps */ 6981 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6982 if (clperm) { 6983 if (perm) { 6984 if (comps) { 6985 for (b = 0; b < fdof; b++) { 6986 ncSet = fcSet = PETSC_FALSE; 6987 if (b % Nc == comps[ncind]) { 6988 ncind = (ncind + 1) % Ncc; 6989 ncSet = PETSC_TRUE; 6990 } 6991 if ((cind < fcdof) && (b == fcdofs[cind])) { 6992 ++cind; 6993 fcSet = PETSC_TRUE; 6994 } 6995 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6996 } 6997 } else { 6998 for (b = 0; b < fdof; b++) { 6999 if ((cind < fcdof) && (b == fcdofs[cind])) { 7000 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7001 ++cind; 7002 } 7003 } 7004 } 7005 } else { 7006 if (comps) { 7007 for (b = 0; b < fdof; b++) { 7008 ncSet = fcSet = PETSC_FALSE; 7009 if (b % Nc == comps[ncind]) { 7010 ncind = (ncind + 1) % Ncc; 7011 ncSet = PETSC_TRUE; 7012 } 7013 if ((cind < fcdof) && (b == fcdofs[cind])) { 7014 ++cind; 7015 fcSet = PETSC_TRUE; 7016 } 7017 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7018 } 7019 } else { 7020 for (b = 0; b < fdof; b++) { 7021 if ((cind < fcdof) && (b == fcdofs[cind])) { 7022 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7023 ++cind; 7024 } 7025 } 7026 } 7027 } 7028 } else { 7029 if (perm) { 7030 if (comps) { 7031 for (b = 0; b < fdof; b++) { 7032 ncSet = fcSet = PETSC_FALSE; 7033 if (b % Nc == comps[ncind]) { 7034 ncind = (ncind + 1) % Ncc; 7035 ncSet = PETSC_TRUE; 7036 } 7037 if ((cind < fcdof) && (b == fcdofs[cind])) { 7038 ++cind; 7039 fcSet = PETSC_TRUE; 7040 } 7041 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7042 } 7043 } else { 7044 for (b = 0; b < fdof; b++) { 7045 if ((cind < fcdof) && (b == fcdofs[cind])) { 7046 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7047 ++cind; 7048 } 7049 } 7050 } 7051 } else { 7052 if (comps) { 7053 for (b = 0; b < fdof; b++) { 7054 ncSet = fcSet = PETSC_FALSE; 7055 if (b % Nc == comps[ncind]) { 7056 ncind = (ncind + 1) % Ncc; 7057 ncSet = PETSC_TRUE; 7058 } 7059 if ((cind < fcdof) && (b == fcdofs[cind])) { 7060 ++cind; 7061 fcSet = PETSC_TRUE; 7062 } 7063 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7064 } 7065 } else { 7066 for (b = 0; b < fdof; b++) { 7067 if ((cind < fcdof) && (b == fcdofs[cind])) { 7068 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7069 ++cind; 7070 } 7071 } 7072 } 7073 } 7074 } 7075 } 7076 *offset += fdof; 7077 PetscFunctionReturn(PETSC_SUCCESS); 7078 } 7079 7080 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7081 { 7082 PetscScalar *array; 7083 const PetscInt *cone, *coneO; 7084 PetscInt pStart, pEnd, p, numPoints, off, dof; 7085 7086 PetscFunctionBeginHot; 7087 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7088 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7089 PetscCall(DMPlexGetCone(dm, point, &cone)); 7090 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7091 PetscCall(VecGetArray(v, &array)); 7092 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7093 const PetscInt cp = !p ? point : cone[p - 1]; 7094 const PetscInt o = !p ? 0 : coneO[p - 1]; 7095 7096 if ((cp < pStart) || (cp >= pEnd)) { 7097 dof = 0; 7098 continue; 7099 } 7100 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7101 /* ADD_VALUES */ 7102 { 7103 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7104 PetscScalar *a; 7105 PetscInt cdof, coff, cind = 0, k; 7106 7107 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7108 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7109 a = &array[coff]; 7110 if (!cdof) { 7111 if (o >= 0) { 7112 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7113 } else { 7114 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7115 } 7116 } else { 7117 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7118 if (o >= 0) { 7119 for (k = 0; k < dof; ++k) { 7120 if ((cind < cdof) && (k == cdofs[cind])) { 7121 ++cind; 7122 continue; 7123 } 7124 a[k] += values[off + k]; 7125 } 7126 } else { 7127 for (k = 0; k < dof; ++k) { 7128 if ((cind < cdof) && (k == cdofs[cind])) { 7129 ++cind; 7130 continue; 7131 } 7132 a[k] += values[off + dof - k - 1]; 7133 } 7134 } 7135 } 7136 } 7137 } 7138 PetscCall(VecRestoreArray(v, &array)); 7139 PetscFunctionReturn(PETSC_SUCCESS); 7140 } 7141 7142 /*@C 7143 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7144 7145 Not collective 7146 7147 Input Parameters: 7148 + dm - The `DM` 7149 . section - The section describing the layout in `v`, or `NULL` to use the default section 7150 . v - The local vector 7151 . point - The point in the `DM` 7152 . values - The array of values 7153 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7154 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7155 7156 Level: intermediate 7157 7158 Note: 7159 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7160 7161 Fortran Note: 7162 `values` must be declared with 7163 .vb 7164 PetscScalar,dimension(:),pointer :: values 7165 .ve 7166 7167 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7168 @*/ 7169 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7170 { 7171 PetscSection clSection; 7172 IS clPoints; 7173 PetscScalar *array; 7174 PetscInt *points = NULL; 7175 const PetscInt *clp, *clperm = NULL; 7176 PetscInt depth, numFields, numPoints, p, clsize; 7177 7178 PetscFunctionBeginHot; 7179 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7180 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7181 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7182 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7183 PetscCall(DMPlexGetDepth(dm, &depth)); 7184 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7185 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7186 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7187 PetscFunctionReturn(PETSC_SUCCESS); 7188 } 7189 /* Get points */ 7190 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7191 for (clsize = 0, p = 0; p < numPoints; p++) { 7192 PetscInt dof; 7193 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7194 clsize += dof; 7195 } 7196 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7197 /* Get array */ 7198 PetscCall(VecGetArray(v, &array)); 7199 /* Get values */ 7200 if (numFields > 0) { 7201 PetscInt offset = 0, f; 7202 for (f = 0; f < numFields; ++f) { 7203 const PetscInt **perms = NULL; 7204 const PetscScalar **flips = NULL; 7205 7206 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7207 switch (mode) { 7208 case INSERT_VALUES: 7209 for (p = 0; p < numPoints; p++) { 7210 const PetscInt point = points[2 * p]; 7211 const PetscInt *perm = perms ? perms[p] : NULL; 7212 const PetscScalar *flip = flips ? flips[p] : NULL; 7213 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7214 } 7215 break; 7216 case INSERT_ALL_VALUES: 7217 for (p = 0; p < numPoints; p++) { 7218 const PetscInt point = points[2 * p]; 7219 const PetscInt *perm = perms ? perms[p] : NULL; 7220 const PetscScalar *flip = flips ? flips[p] : NULL; 7221 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7222 } 7223 break; 7224 case INSERT_BC_VALUES: 7225 for (p = 0; p < numPoints; p++) { 7226 const PetscInt point = points[2 * p]; 7227 const PetscInt *perm = perms ? perms[p] : NULL; 7228 const PetscScalar *flip = flips ? flips[p] : NULL; 7229 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7230 } 7231 break; 7232 case ADD_VALUES: 7233 for (p = 0; p < numPoints; p++) { 7234 const PetscInt point = points[2 * p]; 7235 const PetscInt *perm = perms ? perms[p] : NULL; 7236 const PetscScalar *flip = flips ? flips[p] : NULL; 7237 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7238 } 7239 break; 7240 case ADD_ALL_VALUES: 7241 for (p = 0; p < numPoints; p++) { 7242 const PetscInt point = points[2 * p]; 7243 const PetscInt *perm = perms ? perms[p] : NULL; 7244 const PetscScalar *flip = flips ? flips[p] : NULL; 7245 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7246 } 7247 break; 7248 case ADD_BC_VALUES: 7249 for (p = 0; p < numPoints; p++) { 7250 const PetscInt point = points[2 * p]; 7251 const PetscInt *perm = perms ? perms[p] : NULL; 7252 const PetscScalar *flip = flips ? flips[p] : NULL; 7253 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7254 } 7255 break; 7256 default: 7257 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7258 } 7259 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7260 } 7261 } else { 7262 PetscInt dof, off; 7263 const PetscInt **perms = NULL; 7264 const PetscScalar **flips = NULL; 7265 7266 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7267 switch (mode) { 7268 case INSERT_VALUES: 7269 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7270 const PetscInt point = points[2 * p]; 7271 const PetscInt *perm = perms ? perms[p] : NULL; 7272 const PetscScalar *flip = flips ? flips[p] : NULL; 7273 PetscCall(PetscSectionGetDof(section, point, &dof)); 7274 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7275 } 7276 break; 7277 case INSERT_ALL_VALUES: 7278 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7279 const PetscInt point = points[2 * p]; 7280 const PetscInt *perm = perms ? perms[p] : NULL; 7281 const PetscScalar *flip = flips ? flips[p] : NULL; 7282 PetscCall(PetscSectionGetDof(section, point, &dof)); 7283 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7284 } 7285 break; 7286 case INSERT_BC_VALUES: 7287 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7288 const PetscInt point = points[2 * p]; 7289 const PetscInt *perm = perms ? perms[p] : NULL; 7290 const PetscScalar *flip = flips ? flips[p] : NULL; 7291 PetscCall(PetscSectionGetDof(section, point, &dof)); 7292 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7293 } 7294 break; 7295 case ADD_VALUES: 7296 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7297 const PetscInt point = points[2 * p]; 7298 const PetscInt *perm = perms ? perms[p] : NULL; 7299 const PetscScalar *flip = flips ? flips[p] : NULL; 7300 PetscCall(PetscSectionGetDof(section, point, &dof)); 7301 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7302 } 7303 break; 7304 case ADD_ALL_VALUES: 7305 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7306 const PetscInt point = points[2 * p]; 7307 const PetscInt *perm = perms ? perms[p] : NULL; 7308 const PetscScalar *flip = flips ? flips[p] : NULL; 7309 PetscCall(PetscSectionGetDof(section, point, &dof)); 7310 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7311 } 7312 break; 7313 case ADD_BC_VALUES: 7314 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7315 const PetscInt point = points[2 * p]; 7316 const PetscInt *perm = perms ? perms[p] : NULL; 7317 const PetscScalar *flip = flips ? flips[p] : NULL; 7318 PetscCall(PetscSectionGetDof(section, point, &dof)); 7319 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7320 } 7321 break; 7322 default: 7323 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7324 } 7325 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7326 } 7327 /* Cleanup points */ 7328 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7329 /* Cleanup array */ 7330 PetscCall(VecRestoreArray(v, &array)); 7331 PetscFunctionReturn(PETSC_SUCCESS); 7332 } 7333 7334 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7335 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7336 { 7337 PetscFunctionBegin; 7338 *contains = PETSC_TRUE; 7339 if (label) { 7340 PetscInt fdof; 7341 7342 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7343 if (!*contains) { 7344 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7345 *offset += fdof; 7346 PetscFunctionReturn(PETSC_SUCCESS); 7347 } 7348 } 7349 PetscFunctionReturn(PETSC_SUCCESS); 7350 } 7351 7352 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7353 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) 7354 { 7355 PetscSection clSection; 7356 IS clPoints; 7357 PetscScalar *array; 7358 PetscInt *points = NULL; 7359 const PetscInt *clp; 7360 PetscInt numFields, numPoints, p; 7361 PetscInt offset = 0, f; 7362 7363 PetscFunctionBeginHot; 7364 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7365 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7366 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7367 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7368 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7369 /* Get points */ 7370 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7371 /* Get array */ 7372 PetscCall(VecGetArray(v, &array)); 7373 /* Get values */ 7374 for (f = 0; f < numFields; ++f) { 7375 const PetscInt **perms = NULL; 7376 const PetscScalar **flips = NULL; 7377 PetscBool contains; 7378 7379 if (!fieldActive[f]) { 7380 for (p = 0; p < numPoints * 2; p += 2) { 7381 PetscInt fdof; 7382 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7383 offset += fdof; 7384 } 7385 continue; 7386 } 7387 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7388 switch (mode) { 7389 case INSERT_VALUES: 7390 for (p = 0; p < numPoints; p++) { 7391 const PetscInt point = points[2 * p]; 7392 const PetscInt *perm = perms ? perms[p] : NULL; 7393 const PetscScalar *flip = flips ? flips[p] : NULL; 7394 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7395 if (!contains) continue; 7396 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7397 } 7398 break; 7399 case INSERT_ALL_VALUES: 7400 for (p = 0; p < numPoints; p++) { 7401 const PetscInt point = points[2 * p]; 7402 const PetscInt *perm = perms ? perms[p] : NULL; 7403 const PetscScalar *flip = flips ? flips[p] : NULL; 7404 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7405 if (!contains) continue; 7406 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7407 } 7408 break; 7409 case INSERT_BC_VALUES: 7410 for (p = 0; p < numPoints; p++) { 7411 const PetscInt point = points[2 * p]; 7412 const PetscInt *perm = perms ? perms[p] : NULL; 7413 const PetscScalar *flip = flips ? flips[p] : NULL; 7414 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7415 if (!contains) continue; 7416 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7417 } 7418 break; 7419 case ADD_VALUES: 7420 for (p = 0; p < numPoints; p++) { 7421 const PetscInt point = points[2 * p]; 7422 const PetscInt *perm = perms ? perms[p] : NULL; 7423 const PetscScalar *flip = flips ? flips[p] : NULL; 7424 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7425 if (!contains) continue; 7426 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7427 } 7428 break; 7429 case ADD_ALL_VALUES: 7430 for (p = 0; p < numPoints; p++) { 7431 const PetscInt point = points[2 * p]; 7432 const PetscInt *perm = perms ? perms[p] : NULL; 7433 const PetscScalar *flip = flips ? flips[p] : NULL; 7434 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7435 if (!contains) continue; 7436 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7437 } 7438 break; 7439 default: 7440 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7441 } 7442 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7443 } 7444 /* Cleanup points */ 7445 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7446 /* Cleanup array */ 7447 PetscCall(VecRestoreArray(v, &array)); 7448 PetscFunctionReturn(PETSC_SUCCESS); 7449 } 7450 7451 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7452 { 7453 PetscMPIInt rank; 7454 PetscInt i, j; 7455 7456 PetscFunctionBegin; 7457 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7458 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7459 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7460 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7461 numCIndices = numCIndices ? numCIndices : numRIndices; 7462 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7463 for (i = 0; i < numRIndices; i++) { 7464 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7465 for (j = 0; j < numCIndices; j++) { 7466 #if defined(PETSC_USE_COMPLEX) 7467 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7468 #else 7469 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7470 #endif 7471 } 7472 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7473 } 7474 PetscFunctionReturn(PETSC_SUCCESS); 7475 } 7476 7477 /* 7478 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7479 7480 Input Parameters: 7481 + section - The section for this data layout 7482 . islocal - Is the section (and thus indices being requested) local or global? 7483 . point - The point contributing dofs with these indices 7484 . off - The global offset of this point 7485 . loff - The local offset of each field 7486 . setBC - The flag determining whether to include indices of boundary values 7487 . perm - A permutation of the dofs on this point, or NULL 7488 - indperm - A permutation of the entire indices array, or NULL 7489 7490 Output Parameter: 7491 . indices - Indices for dofs on this point 7492 7493 Level: developer 7494 7495 Note: The indices could be local or global, depending on the value of 'off'. 7496 */ 7497 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7498 { 7499 PetscInt dof; /* The number of unknowns on this point */ 7500 PetscInt cdof; /* The number of constraints on this point */ 7501 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7502 PetscInt cind = 0, k; 7503 7504 PetscFunctionBegin; 7505 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7506 PetscCall(PetscSectionGetDof(section, point, &dof)); 7507 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7508 if (!cdof || setBC) { 7509 for (k = 0; k < dof; ++k) { 7510 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7511 const PetscInt ind = indperm ? indperm[preind] : preind; 7512 7513 indices[ind] = off + k; 7514 } 7515 } else { 7516 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7517 for (k = 0; k < dof; ++k) { 7518 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7519 const PetscInt ind = indperm ? indperm[preind] : preind; 7520 7521 if ((cind < cdof) && (k == cdofs[cind])) { 7522 /* Insert check for returning constrained indices */ 7523 indices[ind] = -(off + k + 1); 7524 ++cind; 7525 } else { 7526 indices[ind] = off + k - (islocal ? 0 : cind); 7527 } 7528 } 7529 } 7530 *loff += dof; 7531 PetscFunctionReturn(PETSC_SUCCESS); 7532 } 7533 7534 /* 7535 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7536 7537 Input Parameters: 7538 + section - a section (global or local) 7539 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7540 . point - point within section 7541 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7542 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7543 . setBC - identify constrained (boundary condition) points via involution. 7544 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7545 . permsoff - offset 7546 - indperm - index permutation 7547 7548 Output Parameter: 7549 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7550 . indices - array to hold indices (as defined by section) of each dof associated with point 7551 7552 Notes: 7553 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7554 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7555 in the local vector. 7556 7557 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7558 significant). It is invalid to call with a global section and setBC=true. 7559 7560 Developer Note: 7561 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7562 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7563 offset could be obtained from the section instead of passing it explicitly as we do now. 7564 7565 Example: 7566 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7567 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7568 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7569 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. 7570 7571 Level: developer 7572 */ 7573 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[]) 7574 { 7575 PetscInt numFields, foff, f; 7576 7577 PetscFunctionBegin; 7578 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7579 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7580 for (f = 0, foff = 0; f < numFields; ++f) { 7581 PetscInt fdof, cfdof; 7582 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7583 PetscInt cind = 0, b; 7584 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7585 7586 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7587 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7588 if (!cfdof || setBC) { 7589 for (b = 0; b < fdof; ++b) { 7590 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7591 const PetscInt ind = indperm ? indperm[preind] : preind; 7592 7593 indices[ind] = off + foff + b; 7594 } 7595 } else { 7596 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7597 for (b = 0; b < fdof; ++b) { 7598 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7599 const PetscInt ind = indperm ? indperm[preind] : preind; 7600 7601 if ((cind < cfdof) && (b == fcdofs[cind])) { 7602 indices[ind] = -(off + foff + b + 1); 7603 ++cind; 7604 } else { 7605 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7606 } 7607 } 7608 } 7609 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7610 foffs[f] += fdof; 7611 } 7612 PetscFunctionReturn(PETSC_SUCCESS); 7613 } 7614 7615 /* 7616 This version believes the globalSection offsets for each field, rather than just the point offset 7617 7618 . foffs - The offset into 'indices' for each field, since it is segregated by field 7619 7620 Notes: 7621 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7622 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7623 */ 7624 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7625 { 7626 PetscInt numFields, foff, f; 7627 7628 PetscFunctionBegin; 7629 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7630 for (f = 0; f < numFields; ++f) { 7631 PetscInt fdof, cfdof; 7632 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7633 PetscInt cind = 0, b; 7634 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7635 7636 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7637 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7638 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7639 if (!cfdof) { 7640 for (b = 0; b < fdof; ++b) { 7641 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7642 const PetscInt ind = indperm ? indperm[preind] : preind; 7643 7644 indices[ind] = foff + b; 7645 } 7646 } else { 7647 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7648 for (b = 0; b < fdof; ++b) { 7649 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7650 const PetscInt ind = indperm ? indperm[preind] : preind; 7651 7652 if ((cind < cfdof) && (b == fcdofs[cind])) { 7653 indices[ind] = -(foff + b + 1); 7654 ++cind; 7655 } else { 7656 indices[ind] = foff + b - cind; 7657 } 7658 } 7659 } 7660 foffs[f] += fdof; 7661 } 7662 PetscFunctionReturn(PETSC_SUCCESS); 7663 } 7664 7665 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7666 { 7667 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7668 7669 PetscFunctionBegin; 7670 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7671 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7672 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7673 for (PetscInt p = 0; p < nPoints; p++) { 7674 PetscInt b = pnts[2 * p]; 7675 PetscInt bSecDof = 0, bOff; 7676 PetscInt cSecDof = 0; 7677 PetscSection indices_section; 7678 7679 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7680 if (!bSecDof) continue; 7681 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7682 indices_section = cSecDof > 0 ? cSec : section; 7683 if (numFields) { 7684 PetscInt fStart[32], fEnd[32]; 7685 7686 fStart[0] = 0; 7687 fEnd[0] = 0; 7688 for (PetscInt f = 0; f < numFields; f++) { 7689 PetscInt fDof = 0; 7690 7691 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7692 fStart[f + 1] = fStart[f] + fDof; 7693 fEnd[f + 1] = fStart[f + 1]; 7694 } 7695 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7696 // only apply permutations on one side 7697 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7698 for (PetscInt f = 0; f < numFields; f++) { 7699 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7700 } 7701 } else { 7702 PetscInt bEnd = 0; 7703 7704 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7705 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7706 7707 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7708 } 7709 } 7710 PetscFunctionReturn(PETSC_SUCCESS); 7711 } 7712 7713 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[]) 7714 { 7715 Mat cMat; 7716 PetscSection aSec, cSec; 7717 IS aIS; 7718 PetscInt aStart = -1, aEnd = -1; 7719 PetscInt sStart = -1, sEnd = -1; 7720 PetscInt cStart = -1, cEnd = -1; 7721 const PetscInt *anchors; 7722 PetscInt numFields, p; 7723 PetscInt newNumPoints = 0, newNumIndices = 0; 7724 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7725 PetscInt oldOffsets[32]; 7726 PetscInt newOffsets[32]; 7727 PetscInt oldOffsetsCopy[32]; 7728 PetscInt newOffsetsCopy[32]; 7729 PetscScalar *modMat = NULL; 7730 PetscBool anyConstrained = PETSC_FALSE; 7731 7732 PetscFunctionBegin; 7733 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7734 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7735 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7736 7737 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7738 /* if there are point-to-point constraints */ 7739 if (aSec) { 7740 PetscCall(PetscArrayzero(newOffsets, 32)); 7741 PetscCall(PetscArrayzero(oldOffsets, 32)); 7742 PetscCall(ISGetIndices(aIS, &anchors)); 7743 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7744 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7745 /* figure out how many points are going to be in the new element matrix 7746 * (we allow double counting, because it's all just going to be summed 7747 * into the global matrix anyway) */ 7748 for (p = 0; p < 2 * numPoints; p += 2) { 7749 PetscInt b = points[p]; 7750 PetscInt bDof = 0, bSecDof = 0; 7751 7752 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7753 if (!bSecDof) continue; 7754 7755 for (PetscInt f = 0; f < numFields; f++) { 7756 PetscInt fDof = 0; 7757 7758 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7759 oldOffsets[f + 1] += fDof; 7760 } 7761 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7762 if (bDof) { 7763 /* this point is constrained */ 7764 /* it is going to be replaced by its anchors */ 7765 PetscInt bOff, q; 7766 7767 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7768 for (q = 0; q < bDof; q++) { 7769 PetscInt a = anchors[bOff + q]; 7770 PetscInt aDof = 0; 7771 7772 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7773 if (aDof) { 7774 anyConstrained = PETSC_TRUE; 7775 newNumPoints += 1; 7776 } 7777 newNumIndices += aDof; 7778 for (PetscInt f = 0; f < numFields; ++f) { 7779 PetscInt fDof = 0; 7780 7781 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7782 newOffsets[f + 1] += fDof; 7783 } 7784 } 7785 } else { 7786 /* this point is not constrained */ 7787 newNumPoints++; 7788 newNumIndices += bSecDof; 7789 for (PetscInt f = 0; f < numFields; ++f) { 7790 PetscInt fDof; 7791 7792 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7793 newOffsets[f + 1] += fDof; 7794 } 7795 } 7796 } 7797 } 7798 if (!anyConstrained) { 7799 if (outNumPoints) *outNumPoints = 0; 7800 if (outNumIndices) *outNumIndices = 0; 7801 if (outPoints) *outPoints = NULL; 7802 if (outMat) *outMat = NULL; 7803 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7804 PetscFunctionReturn(PETSC_SUCCESS); 7805 } 7806 7807 if (outNumPoints) *outNumPoints = newNumPoints; 7808 if (outNumIndices) *outNumIndices = newNumIndices; 7809 7810 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7811 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7812 7813 if (!outPoints && !outMat) { 7814 if (offsets) { 7815 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7816 } 7817 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7818 PetscFunctionReturn(PETSC_SUCCESS); 7819 } 7820 7821 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7822 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7823 7824 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7825 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7826 7827 /* output arrays */ 7828 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7829 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7830 7831 // get the new Points 7832 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7833 PetscInt b = points[2 * p]; 7834 PetscInt bDof = 0, bSecDof = 0, bOff; 7835 7836 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7837 if (!bSecDof) continue; 7838 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7839 if (bDof) { 7840 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7841 for (PetscInt q = 0; q < bDof; q++) { 7842 PetscInt a = anchors[bOff + q], aDof = 0; 7843 7844 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7845 if (aDof) { 7846 newPoints[2 * newP] = a; 7847 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7848 newP++; 7849 } 7850 } 7851 } else { 7852 newPoints[2 * newP] = b; 7853 newPoints[2 * newP + 1] = points[2 * p + 1]; 7854 newP++; 7855 } 7856 } 7857 7858 if (outMat) { 7859 PetscScalar *tmpMat; 7860 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7861 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7862 7863 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7864 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7865 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7866 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7867 7868 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7869 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7870 7871 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7872 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7873 7874 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7875 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7876 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7877 // for each field, insert the anchor modification into modMat 7878 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7879 PetscInt fStart = oldOffsets[f]; 7880 PetscInt fNewStart = newOffsets[f]; 7881 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7882 PetscInt b = points[2 * p]; 7883 PetscInt bDof = 0, bSecDof = 0, bOff; 7884 7885 if (b >= sStart && b < sEnd) { 7886 if (numFields) { 7887 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7888 } else { 7889 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7890 } 7891 } 7892 if (!bSecDof) continue; 7893 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7894 if (bDof) { 7895 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7896 for (PetscInt q = 0; q < bDof; q++, newP++) { 7897 PetscInt a = anchors[bOff + q], aDof = 0; 7898 7899 if (a >= sStart && a < sEnd) { 7900 if (numFields) { 7901 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7902 } else { 7903 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7904 } 7905 } 7906 if (aDof) { 7907 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7908 for (PetscInt d = 0; d < bSecDof; d++) { 7909 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7910 } 7911 } 7912 oNew += aDof; 7913 } 7914 } else { 7915 // Insert the identity matrix in this block 7916 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7917 oNew += bSecDof; 7918 newP++; 7919 } 7920 o += bSecDof; 7921 } 7922 } 7923 7924 *outMat = modMat; 7925 7926 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7927 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7928 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7929 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7930 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7931 } 7932 PetscCall(ISRestoreIndices(aIS, &anchors)); 7933 7934 /* output */ 7935 if (outPoints) { 7936 *outPoints = newPoints; 7937 } else { 7938 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7939 } 7940 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7941 PetscFunctionReturn(PETSC_SUCCESS); 7942 } 7943 7944 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) 7945 { 7946 PetscScalar *modMat = NULL; 7947 PetscInt newNumIndices = -1; 7948 7949 PetscFunctionBegin; 7950 /* 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. 7951 modMat is that matrix C */ 7952 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7953 if (outNumIndices) *outNumIndices = newNumIndices; 7954 if (modMat) { 7955 const PetscScalar *newValues = values; 7956 7957 if (multiplyRight) { 7958 PetscScalar *newNewValues = NULL; 7959 PetscBLASInt M, N, K; 7960 PetscScalar a = 1.0, b = 0.0; 7961 7962 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); 7963 7964 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7965 PetscCall(PetscBLASIntCast(numRows, &N)); 7966 PetscCall(PetscBLASIntCast(numIndices, &K)); 7967 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7968 // row-major to column-major conversion, right multiplication becomes left multiplication 7969 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7970 numCols = newNumIndices; 7971 newValues = newNewValues; 7972 } 7973 7974 if (multiplyLeft) { 7975 PetscScalar *newNewValues = NULL; 7976 PetscBLASInt M, N, K; 7977 PetscScalar a = 1.0, b = 0.0; 7978 7979 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); 7980 7981 PetscCall(PetscBLASIntCast(numCols, &M)); 7982 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7983 PetscCall(PetscBLASIntCast(numIndices, &K)); 7984 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7985 // row-major to column-major conversion, left multiplication becomes right multiplication 7986 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7987 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7988 newValues = newNewValues; 7989 } 7990 *outValues = (PetscScalar *)newValues; 7991 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7992 } 7993 PetscFunctionReturn(PETSC_SUCCESS); 7994 } 7995 7996 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) 7997 { 7998 PetscFunctionBegin; 7999 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 8000 PetscFunctionReturn(PETSC_SUCCESS); 8001 } 8002 8003 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 8004 { 8005 /* Closure ordering */ 8006 PetscSection clSection; 8007 IS clPoints; 8008 const PetscInt *clp; 8009 PetscInt *points; 8010 PetscInt Ncl, Ni = 0; 8011 8012 PetscFunctionBeginHot; 8013 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8014 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 8015 PetscInt dof; 8016 8017 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8018 Ni += dof; 8019 } 8020 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8021 *closureSize = Ni; 8022 PetscFunctionReturn(PETSC_SUCCESS); 8023 } 8024 8025 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) 8026 { 8027 /* Closure ordering */ 8028 PetscSection clSection; 8029 IS clPoints; 8030 const PetscInt *clp; 8031 PetscInt *points; 8032 const PetscInt *clperm = NULL; 8033 /* Dof permutation and sign flips */ 8034 const PetscInt **perms[32] = {NULL}; 8035 const PetscScalar **flips[32] = {NULL}; 8036 PetscScalar *valCopy = NULL; 8037 /* Hanging node constraints */ 8038 PetscInt *pointsC = NULL; 8039 PetscScalar *valuesC = NULL; 8040 PetscInt NclC, NiC; 8041 8042 PetscInt *idx; 8043 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8044 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8045 PetscInt idxStart, idxEnd; 8046 PetscInt nRows, nCols; 8047 8048 PetscFunctionBeginHot; 8049 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8050 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8051 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8052 PetscAssertPointer(numRows, 6); 8053 PetscAssertPointer(numCols, 7); 8054 if (indices) PetscAssertPointer(indices, 8); 8055 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8056 if (values) PetscAssertPointer(values, 10); 8057 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8058 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8059 PetscCall(PetscArrayzero(offsets, 32)); 8060 /* 1) Get points in closure */ 8061 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8062 if (useClPerm) { 8063 PetscInt depth, clsize; 8064 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8065 for (clsize = 0, p = 0; p < Ncl; p++) { 8066 PetscInt dof; 8067 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8068 clsize += dof; 8069 } 8070 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8071 } 8072 /* 2) Get number of indices on these points and field offsets from section */ 8073 for (p = 0; p < Ncl * 2; p += 2) { 8074 PetscInt dof, fdof; 8075 8076 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8077 for (f = 0; f < Nf; ++f) { 8078 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8079 offsets[f + 1] += fdof; 8080 } 8081 Ni += dof; 8082 } 8083 if (*numRows == -1) *numRows = Ni; 8084 if (*numCols == -1) *numCols = Ni; 8085 nRows = *numRows; 8086 nCols = *numCols; 8087 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8088 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8089 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8090 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8091 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8092 for (f = 0; f < PetscMax(1, Nf); ++f) { 8093 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8094 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8095 /* may need to apply sign changes to the element matrix */ 8096 if (values && flips[f]) { 8097 PetscInt foffset = offsets[f]; 8098 8099 for (p = 0; p < Ncl; ++p) { 8100 PetscInt pnt = points[2 * p], fdof; 8101 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8102 8103 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8104 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8105 if (flip) { 8106 PetscInt i, j, k; 8107 8108 if (!valCopy) { 8109 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8110 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8111 *values = valCopy; 8112 } 8113 for (i = 0; i < fdof; ++i) { 8114 PetscScalar fval = flip[i]; 8115 8116 if (multiplyRight) { 8117 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8118 } 8119 if (multiplyLeft) { 8120 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8121 } 8122 } 8123 } 8124 foffset += fdof; 8125 } 8126 } 8127 } 8128 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8129 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8130 if (NclC) { 8131 if (multiplyRight) *numCols = NiC; 8132 if (multiplyLeft) *numRows = NiC; 8133 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8134 for (f = 0; f < PetscMax(1, Nf); ++f) { 8135 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8136 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8137 } 8138 for (f = 0; f < PetscMax(1, Nf); ++f) { 8139 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8140 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8141 } 8142 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8143 Ncl = NclC; 8144 Ni = NiC; 8145 points = pointsC; 8146 if (values) *values = valuesC; 8147 } 8148 /* 5) Calculate indices */ 8149 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8150 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8151 if (Nf) { 8152 PetscInt idxOff; 8153 PetscBool useFieldOffsets; 8154 8155 if (outOffsets) { 8156 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8157 } 8158 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8159 if (useFieldOffsets) { 8160 for (p = 0; p < Ncl; ++p) { 8161 const PetscInt pnt = points[p * 2]; 8162 8163 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8164 } 8165 } else { 8166 for (p = 0; p < Ncl; ++p) { 8167 const PetscInt pnt = points[p * 2]; 8168 8169 if (pnt < idxStart || pnt >= idxEnd) continue; 8170 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8171 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8172 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8173 * global section. */ 8174 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8175 } 8176 } 8177 } else { 8178 PetscInt off = 0, idxOff; 8179 8180 for (p = 0; p < Ncl; ++p) { 8181 const PetscInt pnt = points[p * 2]; 8182 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8183 8184 if (pnt < idxStart || pnt >= idxEnd) continue; 8185 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8186 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8187 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8188 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8189 } 8190 } 8191 /* 6) Cleanup */ 8192 for (f = 0; f < PetscMax(1, Nf); ++f) { 8193 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8194 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8195 } 8196 if (NclC) { 8197 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8198 } else { 8199 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8200 } 8201 8202 if (indices) *indices = idx; 8203 PetscFunctionReturn(PETSC_SUCCESS); 8204 } 8205 8206 /*@C 8207 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8208 8209 Not collective 8210 8211 Input Parameters: 8212 + dm - The `DM` 8213 . section - The `PetscSection` describing the points (a local section) 8214 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8215 . point - The point defining the closure 8216 - useClPerm - Use the closure point permutation if available 8217 8218 Output Parameters: 8219 + numIndices - The number of dof indices in the closure of point with the input sections 8220 . indices - The dof indices 8221 . outOffsets - Array to write the field offsets into, or `NULL` 8222 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8223 8224 Level: advanced 8225 8226 Notes: 8227 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8228 8229 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8230 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8231 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8232 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8233 indices (with the above semantics) are implied. 8234 8235 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8236 `PetscSection`, `DMGetGlobalSection()` 8237 @*/ 8238 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8239 { 8240 PetscInt numRows = -1, numCols = -1; 8241 8242 PetscFunctionBeginHot; 8243 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8244 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8245 *numIndices = numRows; 8246 PetscFunctionReturn(PETSC_SUCCESS); 8247 } 8248 8249 /*@C 8250 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8251 8252 Not collective 8253 8254 Input Parameters: 8255 + dm - The `DM` 8256 . section - The `PetscSection` describing the points (a local section) 8257 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8258 . point - The point defining the closure 8259 - useClPerm - Use the closure point permutation if available 8260 8261 Output Parameters: 8262 + numIndices - The number of dof indices in the closure of point with the input sections 8263 . indices - The dof indices 8264 . outOffsets - Array to write the field offsets into, or `NULL` 8265 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8266 8267 Level: advanced 8268 8269 Notes: 8270 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8271 8272 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8273 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8274 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8275 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8276 indices (with the above semantics) are implied. 8277 8278 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8279 @*/ 8280 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8281 { 8282 PetscFunctionBegin; 8283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8284 PetscAssertPointer(indices, 7); 8285 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8286 PetscFunctionReturn(PETSC_SUCCESS); 8287 } 8288 8289 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8290 { 8291 DM_Plex *mesh = (DM_Plex *)dm->data; 8292 PetscInt *indices; 8293 PetscInt numIndices; 8294 const PetscScalar *valuesOrig = values; 8295 PetscErrorCode ierr; 8296 8297 PetscFunctionBegin; 8298 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8299 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8300 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8301 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8302 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8303 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8304 8305 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8306 8307 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8308 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8309 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8310 if (ierr) { 8311 PetscMPIInt rank; 8312 8313 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8314 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8315 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8316 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8317 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8318 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8319 } 8320 if (mesh->printFEM > 1) { 8321 PetscInt i; 8322 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8323 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8324 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8325 } 8326 8327 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8328 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8329 PetscFunctionReturn(PETSC_SUCCESS); 8330 } 8331 8332 /*@C 8333 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8334 8335 Not collective 8336 8337 Input Parameters: 8338 + dm - The `DM` 8339 . section - The section describing the layout in `v`, or `NULL` to use the default section 8340 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8341 . A - The matrix 8342 . point - The point in the `DM` 8343 . values - The array of values 8344 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8345 8346 Level: intermediate 8347 8348 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8349 @*/ 8350 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8351 { 8352 PetscFunctionBegin; 8353 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8354 PetscFunctionReturn(PETSC_SUCCESS); 8355 } 8356 8357 /*@C 8358 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8359 8360 Not collective 8361 8362 Input Parameters: 8363 + dmRow - The `DM` for the row fields 8364 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8365 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8366 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8367 . dmCol - The `DM` for the column fields 8368 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8369 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8370 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8371 . A - The matrix 8372 . point - The point in the `DM` 8373 . values - The array of values 8374 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8375 8376 Level: intermediate 8377 8378 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8379 @*/ 8380 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) 8381 { 8382 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8383 PetscInt *indicesRow, *indicesCol; 8384 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8385 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8386 8387 PetscErrorCode ierr; 8388 8389 PetscFunctionBegin; 8390 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8391 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8392 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8393 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8394 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8395 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8396 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8397 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8398 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8399 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8400 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8401 8402 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8403 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8404 valuesV1 = valuesV0; 8405 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8406 valuesV2 = valuesV1; 8407 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8408 8409 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8410 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8411 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8412 if (ierr) { 8413 PetscMPIInt rank; 8414 8415 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8416 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8417 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8418 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8419 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8420 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8421 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8422 } 8423 8424 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8425 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8426 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8427 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8428 PetscFunctionReturn(PETSC_SUCCESS); 8429 } 8430 8431 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8432 { 8433 DM_Plex *mesh = (DM_Plex *)dmf->data; 8434 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8435 PetscInt *cpoints = NULL; 8436 PetscInt *findices, *cindices; 8437 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8438 PetscInt foffsets[32], coffsets[32]; 8439 DMPolytopeType ct; 8440 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8441 PetscErrorCode ierr; 8442 8443 PetscFunctionBegin; 8444 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8445 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8446 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8447 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8448 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8449 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8450 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8451 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8452 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8453 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8454 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8455 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8456 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8457 PetscCall(PetscArrayzero(foffsets, 32)); 8458 PetscCall(PetscArrayzero(coffsets, 32)); 8459 /* Column indices */ 8460 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8461 maxFPoints = numCPoints; 8462 /* Compress out points not in the section */ 8463 /* TODO: Squeeze out points with 0 dof as well */ 8464 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8465 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8466 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8467 cpoints[q * 2] = cpoints[p]; 8468 cpoints[q * 2 + 1] = cpoints[p + 1]; 8469 ++q; 8470 } 8471 } 8472 numCPoints = q; 8473 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8474 PetscInt fdof; 8475 8476 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8477 if (!dof) continue; 8478 for (f = 0; f < numFields; ++f) { 8479 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8480 coffsets[f + 1] += fdof; 8481 } 8482 numCIndices += dof; 8483 } 8484 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8485 /* Row indices */ 8486 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8487 { 8488 DMPlexTransform tr; 8489 DMPolytopeType *rct; 8490 PetscInt *rsize, *rcone, *rornt, Nt; 8491 8492 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8493 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8494 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8495 numSubcells = rsize[Nt - 1]; 8496 PetscCall(DMPlexTransformDestroy(&tr)); 8497 } 8498 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8499 for (r = 0, q = 0; r < numSubcells; ++r) { 8500 /* TODO Map from coarse to fine cells */ 8501 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8502 /* Compress out points not in the section */ 8503 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8504 for (p = 0; p < numFPoints * 2; p += 2) { 8505 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8506 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8507 if (!dof) continue; 8508 for (s = 0; s < q; ++s) 8509 if (fpoints[p] == ftotpoints[s * 2]) break; 8510 if (s < q) continue; 8511 ftotpoints[q * 2] = fpoints[p]; 8512 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8513 ++q; 8514 } 8515 } 8516 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8517 } 8518 numFPoints = q; 8519 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8520 PetscInt fdof; 8521 8522 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8523 if (!dof) continue; 8524 for (f = 0; f < numFields; ++f) { 8525 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8526 foffsets[f + 1] += fdof; 8527 } 8528 numFIndices += dof; 8529 } 8530 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8531 8532 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8533 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8534 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8535 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8536 if (numFields) { 8537 const PetscInt **permsF[32] = {NULL}; 8538 const PetscInt **permsC[32] = {NULL}; 8539 8540 for (f = 0; f < numFields; f++) { 8541 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8542 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8543 } 8544 for (p = 0; p < numFPoints; p++) { 8545 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8546 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8547 } 8548 for (p = 0; p < numCPoints; p++) { 8549 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8550 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8551 } 8552 for (f = 0; f < numFields; f++) { 8553 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8554 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8555 } 8556 } else { 8557 const PetscInt **permsF = NULL; 8558 const PetscInt **permsC = NULL; 8559 8560 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8561 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8562 for (p = 0, off = 0; p < numFPoints; p++) { 8563 const PetscInt *perm = permsF ? permsF[p] : NULL; 8564 8565 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8566 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8567 } 8568 for (p = 0, off = 0; p < numCPoints; p++) { 8569 const PetscInt *perm = permsC ? permsC[p] : NULL; 8570 8571 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8572 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8573 } 8574 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8575 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8576 } 8577 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8578 /* TODO: flips */ 8579 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8580 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8581 if (ierr) { 8582 PetscMPIInt rank; 8583 8584 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8585 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8586 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8587 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8588 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8589 } 8590 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8591 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8592 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8593 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8594 PetscFunctionReturn(PETSC_SUCCESS); 8595 } 8596 8597 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8598 { 8599 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8600 PetscInt *cpoints = NULL; 8601 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8602 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8603 DMPolytopeType ct; 8604 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8605 8606 PetscFunctionBegin; 8607 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8608 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8609 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8610 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8611 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8612 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8613 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8614 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8615 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8616 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8617 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8618 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8619 /* Column indices */ 8620 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8621 maxFPoints = numCPoints; 8622 /* Compress out points not in the section */ 8623 /* TODO: Squeeze out points with 0 dof as well */ 8624 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8625 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8626 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8627 cpoints[q * 2] = cpoints[p]; 8628 cpoints[q * 2 + 1] = cpoints[p + 1]; 8629 ++q; 8630 } 8631 } 8632 numCPoints = q; 8633 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8634 PetscInt fdof; 8635 8636 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8637 if (!dof) continue; 8638 for (f = 0; f < numFields; ++f) { 8639 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8640 coffsets[f + 1] += fdof; 8641 } 8642 numCIndices += dof; 8643 } 8644 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8645 /* Row indices */ 8646 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8647 { 8648 DMPlexTransform tr; 8649 DMPolytopeType *rct; 8650 PetscInt *rsize, *rcone, *rornt, Nt; 8651 8652 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8653 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8654 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8655 numSubcells = rsize[Nt - 1]; 8656 PetscCall(DMPlexTransformDestroy(&tr)); 8657 } 8658 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8659 for (r = 0, q = 0; r < numSubcells; ++r) { 8660 /* TODO Map from coarse to fine cells */ 8661 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8662 /* Compress out points not in the section */ 8663 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8664 for (p = 0; p < numFPoints * 2; p += 2) { 8665 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8666 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8667 if (!dof) continue; 8668 for (s = 0; s < q; ++s) 8669 if (fpoints[p] == ftotpoints[s * 2]) break; 8670 if (s < q) continue; 8671 ftotpoints[q * 2] = fpoints[p]; 8672 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8673 ++q; 8674 } 8675 } 8676 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8677 } 8678 numFPoints = q; 8679 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8680 PetscInt fdof; 8681 8682 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8683 if (!dof) continue; 8684 for (f = 0; f < numFields; ++f) { 8685 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8686 foffsets[f + 1] += fdof; 8687 } 8688 numFIndices += dof; 8689 } 8690 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8691 8692 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8693 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8694 if (numFields) { 8695 const PetscInt **permsF[32] = {NULL}; 8696 const PetscInt **permsC[32] = {NULL}; 8697 8698 for (f = 0; f < numFields; f++) { 8699 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8700 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8701 } 8702 for (p = 0; p < numFPoints; p++) { 8703 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8704 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8705 } 8706 for (p = 0; p < numCPoints; p++) { 8707 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8708 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8709 } 8710 for (f = 0; f < numFields; f++) { 8711 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8712 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8713 } 8714 } else { 8715 const PetscInt **permsF = NULL; 8716 const PetscInt **permsC = NULL; 8717 8718 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8719 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8720 for (p = 0, off = 0; p < numFPoints; p++) { 8721 const PetscInt *perm = permsF ? permsF[p] : NULL; 8722 8723 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8724 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8725 } 8726 for (p = 0, off = 0; p < numCPoints; p++) { 8727 const PetscInt *perm = permsC ? permsC[p] : NULL; 8728 8729 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8730 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8731 } 8732 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8733 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8734 } 8735 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8736 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8737 PetscFunctionReturn(PETSC_SUCCESS); 8738 } 8739 8740 /*@ 8741 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8742 8743 Input Parameter: 8744 . dm - The `DMPLEX` object 8745 8746 Output Parameter: 8747 . cellHeight - The height of a cell 8748 8749 Level: developer 8750 8751 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8752 @*/ 8753 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8754 { 8755 DM_Plex *mesh = (DM_Plex *)dm->data; 8756 8757 PetscFunctionBegin; 8758 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8759 PetscAssertPointer(cellHeight, 2); 8760 *cellHeight = mesh->vtkCellHeight; 8761 PetscFunctionReturn(PETSC_SUCCESS); 8762 } 8763 8764 /*@ 8765 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8766 8767 Input Parameters: 8768 + dm - The `DMPLEX` object 8769 - cellHeight - The height of a cell 8770 8771 Level: developer 8772 8773 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8774 @*/ 8775 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8776 { 8777 DM_Plex *mesh = (DM_Plex *)dm->data; 8778 8779 PetscFunctionBegin; 8780 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8781 mesh->vtkCellHeight = cellHeight; 8782 PetscFunctionReturn(PETSC_SUCCESS); 8783 } 8784 8785 /*@ 8786 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8787 8788 Input Parameters: 8789 + dm - The `DMPLEX` object 8790 - ct - The `DMPolytopeType` of the cell 8791 8792 Output Parameters: 8793 + start - The first cell of this type, or `NULL` 8794 - end - The upper bound on this celltype, or `NULL` 8795 8796 Level: advanced 8797 8798 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8799 @*/ 8800 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8801 { 8802 DM_Plex *mesh = (DM_Plex *)dm->data; 8803 DMLabel label; 8804 PetscInt pStart, pEnd; 8805 8806 PetscFunctionBegin; 8807 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8808 if (start) { 8809 PetscAssertPointer(start, 3); 8810 *start = 0; 8811 } 8812 if (end) { 8813 PetscAssertPointer(end, 4); 8814 *end = 0; 8815 } 8816 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8817 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8818 if (mesh->tr) { 8819 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8820 } else { 8821 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8822 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8823 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8824 } 8825 PetscFunctionReturn(PETSC_SUCCESS); 8826 } 8827 8828 /*@ 8829 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8830 8831 Input Parameters: 8832 + dm - The `DMPLEX` object 8833 - depth - The depth for the given point stratum 8834 8835 Output Parameter: 8836 . gsize - The global number of points in the stratum 8837 8838 Level: advanced 8839 8840 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8841 @*/ 8842 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8843 { 8844 PetscSF sf; 8845 const PetscInt *leaves; 8846 PetscInt Nl, loc, start, end, lsize = 0; 8847 8848 PetscFunctionBegin; 8849 PetscCall(DMGetPointSF(dm, &sf)); 8850 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8851 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8852 for (PetscInt p = start; p < end; ++p) { 8853 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8854 if (loc < 0) ++lsize; 8855 } 8856 PetscCallMPI(MPI_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8857 PetscFunctionReturn(PETSC_SUCCESS); 8858 } 8859 8860 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8861 { 8862 PetscSection section, globalSection; 8863 PetscInt *numbers, p; 8864 8865 PetscFunctionBegin; 8866 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8867 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8868 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8869 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8870 PetscCall(PetscSectionSetUp(section)); 8871 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8872 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8873 for (p = pStart; p < pEnd; ++p) { 8874 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8875 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8876 else numbers[p - pStart] += shift; 8877 } 8878 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8879 if (globalSize) { 8880 PetscLayout layout; 8881 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8882 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8883 PetscCall(PetscLayoutDestroy(&layout)); 8884 } 8885 PetscCall(PetscSectionDestroy(§ion)); 8886 PetscCall(PetscSectionDestroy(&globalSection)); 8887 PetscFunctionReturn(PETSC_SUCCESS); 8888 } 8889 8890 /*@ 8891 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8892 8893 Input Parameters: 8894 + dm - The `DMPLEX` object 8895 - includeAll - Whether to include all cells, or just the simplex and box cells 8896 8897 Output Parameter: 8898 . globalCellNumbers - Global cell numbers for all cells on this process 8899 8900 Level: developer 8901 8902 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8903 @*/ 8904 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8905 { 8906 PetscInt cellHeight, cStart, cEnd; 8907 8908 PetscFunctionBegin; 8909 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8910 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8911 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8912 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8913 PetscFunctionReturn(PETSC_SUCCESS); 8914 } 8915 8916 /*@ 8917 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8918 8919 Input Parameter: 8920 . dm - The `DMPLEX` object 8921 8922 Output Parameter: 8923 . globalCellNumbers - Global cell numbers for all cells on this process 8924 8925 Level: developer 8926 8927 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8928 @*/ 8929 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8930 { 8931 DM_Plex *mesh = (DM_Plex *)dm->data; 8932 8933 PetscFunctionBegin; 8934 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8935 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8936 *globalCellNumbers = mesh->globalCellNumbers; 8937 PetscFunctionReturn(PETSC_SUCCESS); 8938 } 8939 8940 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8941 { 8942 PetscInt vStart, vEnd; 8943 8944 PetscFunctionBegin; 8945 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8946 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8947 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8948 PetscFunctionReturn(PETSC_SUCCESS); 8949 } 8950 8951 /*@ 8952 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8953 8954 Input Parameter: 8955 . dm - The `DMPLEX` object 8956 8957 Output Parameter: 8958 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8959 8960 Level: developer 8961 8962 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8963 @*/ 8964 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8965 { 8966 DM_Plex *mesh = (DM_Plex *)dm->data; 8967 8968 PetscFunctionBegin; 8969 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8970 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8971 *globalVertexNumbers = mesh->globalVertexNumbers; 8972 PetscFunctionReturn(PETSC_SUCCESS); 8973 } 8974 8975 /*@ 8976 DMPlexCreatePointNumbering - Create a global numbering for all points. 8977 8978 Collective 8979 8980 Input Parameter: 8981 . dm - The `DMPLEX` object 8982 8983 Output Parameter: 8984 . globalPointNumbers - Global numbers for all points on this process 8985 8986 Level: developer 8987 8988 Notes: 8989 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8990 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8991 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8992 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8993 8994 The partitioned mesh is 8995 ``` 8996 (2)--0--(3)--1--(4) (1)--0--(2) 8997 ``` 8998 and its global numbering is 8999 ``` 9000 (3)--0--(4)--1--(5)--2--(6) 9001 ``` 9002 Then the global numbering is provided as 9003 ``` 9004 [0] Number of indices in set 5 9005 [0] 0 0 9006 [0] 1 1 9007 [0] 2 3 9008 [0] 3 4 9009 [0] 4 -6 9010 [1] Number of indices in set 3 9011 [1] 0 2 9012 [1] 1 5 9013 [1] 2 6 9014 ``` 9015 9016 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9017 @*/ 9018 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 9019 { 9020 IS nums[4]; 9021 PetscInt depths[4], gdepths[4], starts[4]; 9022 PetscInt depth, d, shift = 0; 9023 PetscBool empty = PETSC_FALSE; 9024 9025 PetscFunctionBegin; 9026 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9027 PetscCall(DMPlexGetDepth(dm, &depth)); 9028 // For unstratified meshes use dim instead of depth 9029 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9030 // If any stratum is empty, we must mark all empty 9031 for (d = 0; d <= depth; ++d) { 9032 PetscInt end; 9033 9034 depths[d] = depth - d; 9035 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9036 if (!(starts[d] - end)) empty = PETSC_TRUE; 9037 } 9038 if (empty) 9039 for (d = 0; d <= depth; ++d) { 9040 depths[d] = -1; 9041 starts[d] = -1; 9042 } 9043 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9044 PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9045 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]); 9046 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9047 for (d = 0; d <= depth; ++d) { 9048 PetscInt pStart, pEnd, gsize; 9049 9050 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9051 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9052 shift += gsize; 9053 } 9054 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9055 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9056 PetscFunctionReturn(PETSC_SUCCESS); 9057 } 9058 9059 /*@ 9060 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9061 9062 Collective 9063 9064 Input Parameter: 9065 . dm - The `DMPLEX` object 9066 9067 Output Parameter: 9068 . globalEdgeNumbers - Global numbers for all edges on this process 9069 9070 Level: developer 9071 9072 Notes: 9073 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). 9074 9075 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9076 @*/ 9077 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9078 { 9079 PetscSF sf; 9080 PetscInt eStart, eEnd; 9081 9082 PetscFunctionBegin; 9083 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9084 PetscCall(DMGetPointSF(dm, &sf)); 9085 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9086 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9087 PetscFunctionReturn(PETSC_SUCCESS); 9088 } 9089 9090 /*@ 9091 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9092 9093 Input Parameter: 9094 . dm - The `DMPLEX` object 9095 9096 Output Parameter: 9097 . ranks - The rank field 9098 9099 Options Database Key: 9100 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9101 9102 Level: intermediate 9103 9104 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9105 @*/ 9106 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9107 { 9108 DM rdm; 9109 PetscFE fe; 9110 PetscScalar *r; 9111 PetscMPIInt rank; 9112 DMPolytopeType ct; 9113 PetscInt dim, cStart, cEnd, c; 9114 PetscBool simplex; 9115 9116 PetscFunctionBeginUser; 9117 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9118 PetscAssertPointer(ranks, 2); 9119 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9120 PetscCall(DMClone(dm, &rdm)); 9121 PetscCall(DMGetDimension(rdm, &dim)); 9122 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9123 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9124 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9125 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9126 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9127 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9128 PetscCall(PetscFEDestroy(&fe)); 9129 PetscCall(DMCreateDS(rdm)); 9130 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9131 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9132 PetscCall(VecGetArray(*ranks, &r)); 9133 for (c = cStart; c < cEnd; ++c) { 9134 PetscScalar *lr; 9135 9136 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9137 if (lr) *lr = rank; 9138 } 9139 PetscCall(VecRestoreArray(*ranks, &r)); 9140 PetscCall(DMDestroy(&rdm)); 9141 PetscFunctionReturn(PETSC_SUCCESS); 9142 } 9143 9144 /*@ 9145 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9146 9147 Input Parameters: 9148 + dm - The `DMPLEX` 9149 - label - The `DMLabel` 9150 9151 Output Parameter: 9152 . val - The label value field 9153 9154 Options Database Key: 9155 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9156 9157 Level: intermediate 9158 9159 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9160 @*/ 9161 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9162 { 9163 DM rdm, plex; 9164 Vec lval; 9165 PetscSection section; 9166 PetscFE fe; 9167 PetscScalar *v; 9168 PetscInt dim, pStart, pEnd, p, cStart; 9169 DMPolytopeType ct; 9170 char name[PETSC_MAX_PATH_LEN]; 9171 const char *lname, *prefix; 9172 9173 PetscFunctionBeginUser; 9174 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9175 PetscAssertPointer(label, 2); 9176 PetscAssertPointer(val, 3); 9177 PetscCall(DMClone(dm, &rdm)); 9178 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9179 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9180 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9181 PetscCall(DMDestroy(&plex)); 9182 PetscCall(DMGetDimension(rdm, &dim)); 9183 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9184 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9185 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9186 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9187 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9188 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9189 PetscCall(PetscFEDestroy(&fe)); 9190 PetscCall(DMCreateDS(rdm)); 9191 PetscCall(DMCreateGlobalVector(rdm, val)); 9192 PetscCall(DMCreateLocalVector(rdm, &lval)); 9193 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9194 PetscCall(DMGetLocalSection(rdm, §ion)); 9195 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9196 PetscCall(VecGetArray(lval, &v)); 9197 for (p = pStart; p < pEnd; ++p) { 9198 PetscInt cval, dof, off; 9199 9200 PetscCall(PetscSectionGetDof(section, p, &dof)); 9201 if (!dof) continue; 9202 PetscCall(DMLabelGetValue(label, p, &cval)); 9203 PetscCall(PetscSectionGetOffset(section, p, &off)); 9204 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9205 } 9206 PetscCall(VecRestoreArray(lval, &v)); 9207 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9208 PetscCall(VecDestroy(&lval)); 9209 PetscCall(DMDestroy(&rdm)); 9210 PetscFunctionReturn(PETSC_SUCCESS); 9211 } 9212 9213 /*@ 9214 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9215 9216 Input Parameter: 9217 . dm - The `DMPLEX` object 9218 9219 Level: developer 9220 9221 Notes: 9222 This is a useful diagnostic when creating meshes programmatically. 9223 9224 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9225 9226 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9227 @*/ 9228 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9229 { 9230 PetscSection coneSection, supportSection; 9231 const PetscInt *cone, *support; 9232 PetscInt coneSize, c, supportSize, s; 9233 PetscInt pStart, pEnd, p, pp, csize, ssize; 9234 PetscBool storagecheck = PETSC_TRUE; 9235 9236 PetscFunctionBegin; 9237 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9238 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9239 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9240 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9241 /* Check that point p is found in the support of its cone points, and vice versa */ 9242 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9243 for (p = pStart; p < pEnd; ++p) { 9244 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9245 PetscCall(DMPlexGetCone(dm, p, &cone)); 9246 for (c = 0; c < coneSize; ++c) { 9247 PetscBool dup = PETSC_FALSE; 9248 PetscInt d; 9249 for (d = c - 1; d >= 0; --d) { 9250 if (cone[c] == cone[d]) { 9251 dup = PETSC_TRUE; 9252 break; 9253 } 9254 } 9255 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9256 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9257 for (s = 0; s < supportSize; ++s) { 9258 if (support[s] == p) break; 9259 } 9260 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9261 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9262 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9263 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9264 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9265 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9266 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9267 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]); 9268 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9269 } 9270 } 9271 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9272 if (p != pp) { 9273 storagecheck = PETSC_FALSE; 9274 continue; 9275 } 9276 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9277 PetscCall(DMPlexGetSupport(dm, p, &support)); 9278 for (s = 0; s < supportSize; ++s) { 9279 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9280 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9281 for (c = 0; c < coneSize; ++c) { 9282 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9283 if (cone[c] != pp) { 9284 c = 0; 9285 break; 9286 } 9287 if (cone[c] == p) break; 9288 } 9289 if (c >= coneSize) { 9290 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9291 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9292 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9293 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9294 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9295 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9296 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9297 } 9298 } 9299 } 9300 if (storagecheck) { 9301 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9302 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9303 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9304 } 9305 PetscFunctionReturn(PETSC_SUCCESS); 9306 } 9307 9308 /* 9309 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. 9310 */ 9311 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9312 { 9313 DMPolytopeType cct; 9314 PetscInt ptpoints[4]; 9315 const PetscInt *cone, *ccone, *ptcone; 9316 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9317 9318 PetscFunctionBegin; 9319 *unsplit = 0; 9320 switch (ct) { 9321 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9322 ptpoints[npt++] = c; 9323 break; 9324 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9325 PetscCall(DMPlexGetCone(dm, c, &cone)); 9326 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9327 for (cp = 0; cp < coneSize; ++cp) { 9328 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9329 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9330 } 9331 break; 9332 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9333 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9334 PetscCall(DMPlexGetCone(dm, c, &cone)); 9335 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9336 for (cp = 0; cp < coneSize; ++cp) { 9337 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9338 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9339 for (ccp = 0; ccp < cconeSize; ++ccp) { 9340 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9341 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9342 PetscInt p; 9343 for (p = 0; p < npt; ++p) 9344 if (ptpoints[p] == ccone[ccp]) break; 9345 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9346 } 9347 } 9348 } 9349 break; 9350 default: 9351 break; 9352 } 9353 for (pt = 0; pt < npt; ++pt) { 9354 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9355 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9356 } 9357 PetscFunctionReturn(PETSC_SUCCESS); 9358 } 9359 9360 /*@ 9361 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9362 9363 Input Parameters: 9364 + dm - The `DMPLEX` object 9365 - cellHeight - Normally 0 9366 9367 Level: developer 9368 9369 Notes: 9370 This is a useful diagnostic when creating meshes programmatically. 9371 Currently applicable only to homogeneous simplex or tensor meshes. 9372 9373 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9374 9375 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9376 @*/ 9377 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9378 { 9379 DMPlexInterpolatedFlag interp; 9380 DMPolytopeType ct; 9381 PetscInt vStart, vEnd, cStart, cEnd, c; 9382 9383 PetscFunctionBegin; 9384 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9385 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9386 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9387 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9388 for (c = cStart; c < cEnd; ++c) { 9389 PetscInt *closure = NULL; 9390 PetscInt coneSize, closureSize, cl, Nv = 0; 9391 9392 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9393 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9394 if (interp == DMPLEX_INTERPOLATED_FULL) { 9395 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9396 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)); 9397 } 9398 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9399 for (cl = 0; cl < closureSize * 2; cl += 2) { 9400 const PetscInt p = closure[cl]; 9401 if ((p >= vStart) && (p < vEnd)) ++Nv; 9402 } 9403 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9404 /* Special Case: Tensor faces with identified vertices */ 9405 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9406 PetscInt unsplit; 9407 9408 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9409 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9410 } 9411 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)); 9412 } 9413 PetscFunctionReturn(PETSC_SUCCESS); 9414 } 9415 9416 /*@ 9417 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9418 9419 Collective 9420 9421 Input Parameters: 9422 + dm - The `DMPLEX` object 9423 - cellHeight - Normally 0 9424 9425 Level: developer 9426 9427 Notes: 9428 This is a useful diagnostic when creating meshes programmatically. 9429 This routine is only relevant for meshes that are fully interpolated across all ranks. 9430 It will error out if a partially interpolated mesh is given on some rank. 9431 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9432 9433 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9434 9435 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9436 @*/ 9437 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9438 { 9439 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9440 DMPlexInterpolatedFlag interpEnum; 9441 9442 PetscFunctionBegin; 9443 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9444 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9445 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9446 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9447 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9448 PetscFunctionReturn(PETSC_SUCCESS); 9449 } 9450 9451 PetscCall(DMGetDimension(dm, &dim)); 9452 PetscCall(DMPlexGetDepth(dm, &depth)); 9453 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9454 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9455 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9456 for (c = cStart; c < cEnd; ++c) { 9457 const PetscInt *cone, *ornt, *faceSizes, *faces; 9458 const DMPolytopeType *faceTypes; 9459 DMPolytopeType ct; 9460 PetscInt numFaces, coneSize, f; 9461 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9462 9463 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9464 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9465 if (unsplit) continue; 9466 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9467 PetscCall(DMPlexGetCone(dm, c, &cone)); 9468 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9469 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9470 for (cl = 0; cl < closureSize * 2; cl += 2) { 9471 const PetscInt p = closure[cl]; 9472 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9473 } 9474 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9475 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); 9476 for (f = 0; f < numFaces; ++f) { 9477 DMPolytopeType fct; 9478 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9479 9480 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9481 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9482 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9483 const PetscInt p = fclosure[cl]; 9484 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9485 } 9486 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]); 9487 for (v = 0; v < fnumCorners; ++v) { 9488 if (fclosure[v] != faces[fOff + v]) { 9489 PetscInt v1; 9490 9491 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9492 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9493 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9494 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9495 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9496 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]); 9497 } 9498 } 9499 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9500 fOff += faceSizes[f]; 9501 } 9502 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9503 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9504 } 9505 } 9506 PetscFunctionReturn(PETSC_SUCCESS); 9507 } 9508 9509 /*@ 9510 DMPlexCheckGeometry - Check the geometry of mesh cells 9511 9512 Input Parameter: 9513 . dm - The `DMPLEX` object 9514 9515 Level: developer 9516 9517 Notes: 9518 This is a useful diagnostic when creating meshes programmatically. 9519 9520 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9521 9522 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9523 @*/ 9524 PetscErrorCode DMPlexCheckGeometry(DM dm) 9525 { 9526 Vec coordinates; 9527 PetscReal detJ, J[9], refVol = 1.0; 9528 PetscReal vol; 9529 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9530 9531 PetscFunctionBegin; 9532 PetscCall(DMGetDimension(dm, &dim)); 9533 PetscCall(DMGetCoordinateDim(dm, &dE)); 9534 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9535 PetscCall(DMPlexGetDepth(dm, &depth)); 9536 for (d = 0; d < dim; ++d) refVol *= 2.0; 9537 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9538 /* Make sure local coordinates are created, because that step is collective */ 9539 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9540 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9541 for (c = cStart; c < cEnd; ++c) { 9542 DMPolytopeType ct; 9543 PetscInt unsplit; 9544 PetscBool ignoreZeroVol = PETSC_FALSE; 9545 9546 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9547 switch (ct) { 9548 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9549 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9550 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9551 ignoreZeroVol = PETSC_TRUE; 9552 break; 9553 default: 9554 break; 9555 } 9556 switch (ct) { 9557 case DM_POLYTOPE_TRI_PRISM: 9558 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9559 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9560 case DM_POLYTOPE_PYRAMID: 9561 continue; 9562 default: 9563 break; 9564 } 9565 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9566 if (unsplit) continue; 9567 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9568 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); 9569 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9570 /* This should work with periodicity since DG coordinates should be used */ 9571 if (depth > 1) { 9572 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9573 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); 9574 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9575 } 9576 } 9577 PetscFunctionReturn(PETSC_SUCCESS); 9578 } 9579 9580 /*@ 9581 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9582 9583 Collective 9584 9585 Input Parameters: 9586 + dm - The `DMPLEX` object 9587 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9588 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9589 9590 Level: developer 9591 9592 Notes: 9593 This is mainly intended for debugging/testing purposes. 9594 9595 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9596 9597 Extra roots can come from periodic cuts, where additional points appear on the boundary 9598 9599 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9600 @*/ 9601 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9602 { 9603 PetscInt l, nleaves, nroots, overlap; 9604 const PetscInt *locals; 9605 const PetscSFNode *remotes; 9606 PetscBool distributed; 9607 MPI_Comm comm; 9608 PetscMPIInt rank; 9609 9610 PetscFunctionBegin; 9611 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9612 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9613 else pointSF = dm->sf; 9614 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9615 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9616 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9617 { 9618 PetscMPIInt mpiFlag; 9619 9620 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9621 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9622 } 9623 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9624 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9625 if (!distributed) { 9626 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); 9627 PetscFunctionReturn(PETSC_SUCCESS); 9628 } 9629 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); 9630 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9631 9632 /* Check SF graph is compatible with DMPlex chart */ 9633 { 9634 PetscInt pStart, pEnd, maxLeaf; 9635 9636 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9637 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9638 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9639 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9640 } 9641 9642 /* Check Point SF has no local points referenced */ 9643 for (l = 0; l < nleaves; l++) { 9644 PetscMPIInt irank; 9645 9646 PetscCall(PetscMPIIntCast(remotes[l].rank, &irank)); 9647 PetscAssert(irank != rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%d,%" PetscInt_FMT ")", locals ? locals[l] : l, irank, remotes[l].index); 9648 } 9649 9650 /* Check there are no cells in interface */ 9651 if (!overlap) { 9652 PetscInt cellHeight, cStart, cEnd; 9653 9654 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9655 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9656 for (l = 0; l < nleaves; ++l) { 9657 const PetscInt point = locals ? locals[l] : l; 9658 9659 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9660 } 9661 } 9662 9663 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9664 { 9665 const PetscInt *rootdegree; 9666 9667 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9668 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9669 for (l = 0; l < nleaves; ++l) { 9670 const PetscInt point = locals ? locals[l] : l; 9671 const PetscInt *cone; 9672 PetscInt coneSize, c, idx; 9673 9674 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9675 PetscCall(DMPlexGetCone(dm, point, &cone)); 9676 for (c = 0; c < coneSize; ++c) { 9677 if (!rootdegree[cone[c]]) { 9678 if (locals) { 9679 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9680 } else { 9681 idx = (cone[c] < nleaves) ? cone[c] : -1; 9682 } 9683 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9684 } 9685 } 9686 } 9687 } 9688 PetscFunctionReturn(PETSC_SUCCESS); 9689 } 9690 9691 /*@ 9692 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9693 9694 Collective 9695 9696 Input Parameter: 9697 . dm - The `DMPLEX` object 9698 9699 Level: developer 9700 9701 Notes: 9702 This is mainly intended for debugging/testing purposes. 9703 9704 Other cell types which are disconnected would be caught by the symmetry and face checks. 9705 9706 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9707 9708 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9709 @*/ 9710 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9711 { 9712 PetscInt pStart, pEnd, vStart, vEnd; 9713 9714 PetscFunctionBegin; 9715 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9716 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9717 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9718 for (PetscInt v = vStart; v < vEnd; ++v) { 9719 PetscInt suppSize; 9720 9721 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9722 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9723 } 9724 PetscFunctionReturn(PETSC_SUCCESS); 9725 } 9726 9727 /*@ 9728 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9729 9730 Input Parameter: 9731 . dm - The `DMPLEX` object 9732 9733 Level: developer 9734 9735 Notes: 9736 This is a useful diagnostic when creating meshes programmatically. 9737 9738 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9739 9740 Currently does not include `DMPlexCheckCellShape()`. 9741 9742 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9743 @*/ 9744 PetscErrorCode DMPlexCheck(DM dm) 9745 { 9746 PetscInt cellHeight; 9747 9748 PetscFunctionBegin; 9749 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9750 PetscCall(DMPlexCheckSymmetry(dm)); 9751 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9752 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9753 PetscCall(DMPlexCheckGeometry(dm)); 9754 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9755 PetscCall(DMPlexCheckInterfaceCones(dm)); 9756 PetscCall(DMPlexCheckOrphanVertices(dm)); 9757 PetscFunctionReturn(PETSC_SUCCESS); 9758 } 9759 9760 typedef struct cell_stats { 9761 PetscReal min, max, sum, squaresum; 9762 PetscInt count; 9763 } cell_stats_t; 9764 9765 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9766 { 9767 PetscInt i, N = *len; 9768 9769 for (i = 0; i < N; i++) { 9770 cell_stats_t *A = (cell_stats_t *)a; 9771 cell_stats_t *B = (cell_stats_t *)b; 9772 9773 B->min = PetscMin(A->min, B->min); 9774 B->max = PetscMax(A->max, B->max); 9775 B->sum += A->sum; 9776 B->squaresum += A->squaresum; 9777 B->count += A->count; 9778 } 9779 } 9780 9781 /*@ 9782 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9783 9784 Collective 9785 9786 Input Parameters: 9787 + dm - The `DMPLEX` object 9788 . output - If true, statistics will be displayed on `stdout` 9789 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9790 9791 Level: developer 9792 9793 Notes: 9794 This is mainly intended for debugging/testing purposes. 9795 9796 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9797 9798 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9799 @*/ 9800 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9801 { 9802 DM dmCoarse; 9803 cell_stats_t stats, globalStats; 9804 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9805 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9806 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9807 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9808 PetscMPIInt rank, size; 9809 9810 PetscFunctionBegin; 9811 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9812 stats.min = PETSC_MAX_REAL; 9813 stats.max = PETSC_MIN_REAL; 9814 stats.sum = stats.squaresum = 0.; 9815 stats.count = 0; 9816 9817 PetscCallMPI(MPI_Comm_size(comm, &size)); 9818 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9819 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9820 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9821 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9822 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9823 for (c = cStart; c < cEnd; c++) { 9824 PetscInt i; 9825 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9826 9827 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9828 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9829 for (i = 0; i < PetscSqr(cdim); ++i) { 9830 frobJ += J[i] * J[i]; 9831 frobInvJ += invJ[i] * invJ[i]; 9832 } 9833 cond2 = frobJ * frobInvJ; 9834 cond = PetscSqrtReal(cond2); 9835 9836 stats.min = PetscMin(stats.min, cond); 9837 stats.max = PetscMax(stats.max, cond); 9838 stats.sum += cond; 9839 stats.squaresum += cond2; 9840 stats.count++; 9841 if (output && cond > limit) { 9842 PetscSection coordSection; 9843 Vec coordsLocal; 9844 PetscScalar *coords = NULL; 9845 PetscInt Nv, d, clSize, cl, *closure = NULL; 9846 9847 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9848 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9849 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9850 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9851 for (i = 0; i < Nv / cdim; ++i) { 9852 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9853 for (d = 0; d < cdim; ++d) { 9854 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9855 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9856 } 9857 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9858 } 9859 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9860 for (cl = 0; cl < clSize * 2; cl += 2) { 9861 const PetscInt edge = closure[cl]; 9862 9863 if ((edge >= eStart) && (edge < eEnd)) { 9864 PetscReal len; 9865 9866 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9867 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9868 } 9869 } 9870 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9871 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9872 } 9873 } 9874 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9875 9876 if (size > 1) { 9877 PetscMPIInt blockLengths[2] = {4, 1}; 9878 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9879 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9880 MPI_Op statReduce; 9881 9882 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9883 PetscCallMPI(MPI_Type_commit(&statType)); 9884 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9885 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9886 PetscCallMPI(MPI_Op_free(&statReduce)); 9887 PetscCallMPI(MPI_Type_free(&statType)); 9888 } else { 9889 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9890 } 9891 if (rank == 0) { 9892 count = globalStats.count; 9893 min = globalStats.min; 9894 max = globalStats.max; 9895 mean = globalStats.sum / globalStats.count; 9896 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9897 } 9898 9899 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)); 9900 PetscCall(PetscFree2(J, invJ)); 9901 9902 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9903 if (dmCoarse) { 9904 PetscBool isplex; 9905 9906 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9907 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9908 } 9909 PetscFunctionReturn(PETSC_SUCCESS); 9910 } 9911 9912 /*@ 9913 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9914 orthogonal quality below given tolerance. 9915 9916 Collective 9917 9918 Input Parameters: 9919 + dm - The `DMPLEX` object 9920 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9921 - atol - [0, 1] Absolute tolerance for tagging cells. 9922 9923 Output Parameters: 9924 + OrthQual - `Vec` containing orthogonal quality per cell 9925 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9926 9927 Options Database Keys: 9928 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9929 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9930 9931 Level: intermediate 9932 9933 Notes: 9934 Orthogonal quality is given by the following formula\: 9935 9936 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9937 9938 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 9939 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9940 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9941 calculating the cosine of the angle between these vectors. 9942 9943 Orthogonal quality ranges from 1 (best) to 0 (worst). 9944 9945 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9946 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9947 9948 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9949 9950 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9951 @*/ 9952 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9953 { 9954 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9955 PetscInt *idx; 9956 PetscScalar *oqVals; 9957 const PetscScalar *cellGeomArr, *faceGeomArr; 9958 PetscReal *ci, *fi, *Ai; 9959 MPI_Comm comm; 9960 Vec cellgeom, facegeom; 9961 DM dmFace, dmCell; 9962 IS glob; 9963 ISLocalToGlobalMapping ltog; 9964 PetscViewer vwr; 9965 9966 PetscFunctionBegin; 9967 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9968 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9969 PetscAssertPointer(OrthQual, 4); 9970 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9971 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9972 PetscCall(DMGetDimension(dm, &nc)); 9973 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9974 { 9975 DMPlexInterpolatedFlag interpFlag; 9976 9977 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9978 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9979 PetscMPIInt rank; 9980 9981 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9982 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9983 } 9984 } 9985 if (OrthQualLabel) { 9986 PetscAssertPointer(OrthQualLabel, 5); 9987 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9988 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9989 } else { 9990 *OrthQualLabel = NULL; 9991 } 9992 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9993 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9994 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9995 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9996 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9997 PetscCall(VecCreate(comm, OrthQual)); 9998 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9999 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 10000 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 10001 PetscCall(VecSetUp(*OrthQual)); 10002 PetscCall(ISDestroy(&glob)); 10003 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 10004 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 10005 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 10006 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 10007 PetscCall(VecGetDM(cellgeom, &dmCell)); 10008 PetscCall(VecGetDM(facegeom, &dmFace)); 10009 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 10010 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 10011 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 10012 PetscInt cellarr[2], *adj = NULL; 10013 PetscScalar *cArr, *fArr; 10014 PetscReal minvalc = 1.0, minvalf = 1.0; 10015 PetscFVCellGeom *cg; 10016 10017 idx[cellIter] = cell - cStart; 10018 cellarr[0] = cell; 10019 /* Make indexing into cellGeom easier */ 10020 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10021 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10022 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10023 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10024 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10025 PetscInt i; 10026 const PetscInt neigh = adj[cellneigh]; 10027 PetscReal normci = 0, normfi = 0, normai = 0; 10028 PetscFVCellGeom *cgneigh; 10029 PetscFVFaceGeom *fg; 10030 10031 /* Don't count ourselves in the neighbor list */ 10032 if (neigh == cell) continue; 10033 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10034 cellarr[1] = neigh; 10035 { 10036 PetscInt numcovpts; 10037 const PetscInt *covpts; 10038 10039 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10040 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10041 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10042 } 10043 10044 /* Compute c_i, f_i and their norms */ 10045 for (i = 0; i < nc; i++) { 10046 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10047 fi[i] = fg->centroid[i] - cg->centroid[i]; 10048 Ai[i] = fg->normal[i]; 10049 normci += PetscPowReal(ci[i], 2); 10050 normfi += PetscPowReal(fi[i], 2); 10051 normai += PetscPowReal(Ai[i], 2); 10052 } 10053 normci = PetscSqrtReal(normci); 10054 normfi = PetscSqrtReal(normfi); 10055 normai = PetscSqrtReal(normai); 10056 10057 /* Normalize and compute for each face-cell-normal pair */ 10058 for (i = 0; i < nc; i++) { 10059 ci[i] = ci[i] / normci; 10060 fi[i] = fi[i] / normfi; 10061 Ai[i] = Ai[i] / normai; 10062 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10063 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10064 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10065 } 10066 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10067 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10068 } 10069 PetscCall(PetscFree(adj)); 10070 PetscCall(PetscFree2(cArr, fArr)); 10071 /* Defer to cell if they're equal */ 10072 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10073 if (OrthQualLabel) { 10074 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10075 } 10076 } 10077 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10078 PetscCall(VecAssemblyBegin(*OrthQual)); 10079 PetscCall(VecAssemblyEnd(*OrthQual)); 10080 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10081 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10082 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10083 if (OrthQualLabel) { 10084 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10085 } 10086 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10087 PetscCall(PetscViewerDestroy(&vwr)); 10088 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10089 PetscFunctionReturn(PETSC_SUCCESS); 10090 } 10091 10092 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10093 * interpolator construction */ 10094 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10095 { 10096 PetscSection section, newSection, gsection; 10097 PetscSF sf; 10098 PetscBool hasConstraints, ghasConstraints; 10099 10100 PetscFunctionBegin; 10101 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10102 PetscAssertPointer(odm, 2); 10103 PetscCall(DMGetLocalSection(dm, §ion)); 10104 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10105 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10106 if (!ghasConstraints) { 10107 PetscCall(PetscObjectReference((PetscObject)dm)); 10108 *odm = dm; 10109 PetscFunctionReturn(PETSC_SUCCESS); 10110 } 10111 PetscCall(DMClone(dm, odm)); 10112 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10113 PetscCall(DMGetLocalSection(*odm, &newSection)); 10114 PetscCall(DMGetPointSF(*odm, &sf)); 10115 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10116 PetscCall(DMSetGlobalSection(*odm, gsection)); 10117 PetscCall(PetscSectionDestroy(&gsection)); 10118 PetscFunctionReturn(PETSC_SUCCESS); 10119 } 10120 10121 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10122 { 10123 DM dmco, dmfo; 10124 Mat interpo; 10125 Vec rscale; 10126 Vec cglobalo, clocal; 10127 Vec fglobal, fglobalo, flocal; 10128 PetscBool regular; 10129 10130 PetscFunctionBegin; 10131 PetscCall(DMGetFullDM(dmc, &dmco)); 10132 PetscCall(DMGetFullDM(dmf, &dmfo)); 10133 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10134 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10135 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10136 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10137 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10138 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10139 PetscCall(VecSet(cglobalo, 0.)); 10140 PetscCall(VecSet(clocal, 0.)); 10141 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10142 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10143 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10144 PetscCall(VecSet(fglobal, 0.)); 10145 PetscCall(VecSet(fglobalo, 0.)); 10146 PetscCall(VecSet(flocal, 0.)); 10147 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10148 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10149 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10150 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10151 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10152 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10153 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10154 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10155 *shift = fglobal; 10156 PetscCall(VecDestroy(&flocal)); 10157 PetscCall(VecDestroy(&fglobalo)); 10158 PetscCall(VecDestroy(&clocal)); 10159 PetscCall(VecDestroy(&cglobalo)); 10160 PetscCall(VecDestroy(&rscale)); 10161 PetscCall(MatDestroy(&interpo)); 10162 PetscCall(DMDestroy(&dmfo)); 10163 PetscCall(DMDestroy(&dmco)); 10164 PetscFunctionReturn(PETSC_SUCCESS); 10165 } 10166 10167 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10168 { 10169 PetscObject shifto; 10170 Vec shift; 10171 10172 PetscFunctionBegin; 10173 if (!interp) { 10174 Vec rscale; 10175 10176 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10177 PetscCall(VecDestroy(&rscale)); 10178 } else { 10179 PetscCall(PetscObjectReference((PetscObject)interp)); 10180 } 10181 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10182 if (!shifto) { 10183 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10184 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10185 shifto = (PetscObject)shift; 10186 PetscCall(VecDestroy(&shift)); 10187 } 10188 shift = (Vec)shifto; 10189 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10190 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10191 PetscCall(MatDestroy(&interp)); 10192 PetscFunctionReturn(PETSC_SUCCESS); 10193 } 10194 10195 /* Pointwise interpolation 10196 Just code FEM for now 10197 u^f = I u^c 10198 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10199 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10200 I_{ij} = psi^f_i phi^c_j 10201 */ 10202 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10203 { 10204 PetscSection gsc, gsf; 10205 PetscInt m, n; 10206 void *ctx; 10207 DM cdm; 10208 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10209 10210 PetscFunctionBegin; 10211 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10212 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10213 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10214 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10215 10216 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10217 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10218 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10219 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10220 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10221 10222 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10223 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10224 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10225 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10226 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10227 if (scaling) { 10228 /* Use naive scaling */ 10229 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10230 } 10231 PetscFunctionReturn(PETSC_SUCCESS); 10232 } 10233 10234 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10235 { 10236 VecScatter ctx; 10237 10238 PetscFunctionBegin; 10239 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10240 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10241 PetscCall(VecScatterDestroy(&ctx)); 10242 PetscFunctionReturn(PETSC_SUCCESS); 10243 } 10244 10245 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[]) 10246 { 10247 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10248 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10249 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10250 } 10251 10252 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10253 { 10254 DM dmc; 10255 PetscDS ds; 10256 Vec ones, locmass; 10257 IS cellIS; 10258 PetscFormKey key; 10259 PetscInt depth; 10260 10261 PetscFunctionBegin; 10262 PetscCall(DMClone(dm, &dmc)); 10263 PetscCall(DMCopyDisc(dm, dmc)); 10264 PetscCall(DMGetDS(dmc, &ds)); 10265 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10266 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10267 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10268 else PetscCall(DMGetLocalVector(dm, &locmass)); 10269 PetscCall(DMGetLocalVector(dm, &ones)); 10270 PetscCall(DMPlexGetDepth(dm, &depth)); 10271 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10272 PetscCall(VecSet(locmass, 0.0)); 10273 PetscCall(VecSet(ones, 1.0)); 10274 key.label = NULL; 10275 key.value = 0; 10276 key.field = 0; 10277 key.part = 0; 10278 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10279 PetscCall(ISDestroy(&cellIS)); 10280 if (mass) { 10281 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10282 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10283 } 10284 PetscCall(DMRestoreLocalVector(dm, &ones)); 10285 if (lmass) *lmass = locmass; 10286 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10287 PetscCall(DMDestroy(&dmc)); 10288 PetscFunctionReturn(PETSC_SUCCESS); 10289 } 10290 10291 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10292 { 10293 PetscSection gsc, gsf; 10294 PetscInt m, n; 10295 void *ctx; 10296 DM cdm; 10297 PetscBool regular; 10298 10299 PetscFunctionBegin; 10300 if (dmFine == dmCoarse) { 10301 DM dmc; 10302 PetscDS ds; 10303 PetscWeakForm wf; 10304 Vec u; 10305 IS cellIS; 10306 PetscFormKey key; 10307 PetscInt depth; 10308 10309 PetscCall(DMClone(dmFine, &dmc)); 10310 PetscCall(DMCopyDisc(dmFine, dmc)); 10311 PetscCall(DMGetDS(dmc, &ds)); 10312 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10313 PetscCall(PetscWeakFormClear(wf)); 10314 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10315 PetscCall(DMCreateMatrix(dmc, mass)); 10316 PetscCall(DMGetLocalVector(dmc, &u)); 10317 PetscCall(DMPlexGetDepth(dmc, &depth)); 10318 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10319 PetscCall(MatZeroEntries(*mass)); 10320 key.label = NULL; 10321 key.value = 0; 10322 key.field = 0; 10323 key.part = 0; 10324 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10325 PetscCall(ISDestroy(&cellIS)); 10326 PetscCall(DMRestoreLocalVector(dmc, &u)); 10327 PetscCall(DMDestroy(&dmc)); 10328 } else { 10329 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10330 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10331 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10332 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10333 10334 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10335 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10336 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10337 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10338 10339 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10340 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10341 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10342 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10343 } 10344 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10345 PetscFunctionReturn(PETSC_SUCCESS); 10346 } 10347 10348 /*@ 10349 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10350 10351 Input Parameter: 10352 . dm - The `DMPLEX` object 10353 10354 Output Parameter: 10355 . regular - The flag 10356 10357 Level: intermediate 10358 10359 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10360 @*/ 10361 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10362 { 10363 PetscFunctionBegin; 10364 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10365 PetscAssertPointer(regular, 2); 10366 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10367 PetscFunctionReturn(PETSC_SUCCESS); 10368 } 10369 10370 /*@ 10371 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10372 10373 Input Parameters: 10374 + dm - The `DMPLEX` object 10375 - regular - The flag 10376 10377 Level: intermediate 10378 10379 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10380 @*/ 10381 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10382 { 10383 PetscFunctionBegin; 10384 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10385 ((DM_Plex *)dm->data)->regularRefinement = regular; 10386 PetscFunctionReturn(PETSC_SUCCESS); 10387 } 10388 10389 /*@ 10390 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10391 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10392 10393 Not Collective 10394 10395 Input Parameter: 10396 . dm - The `DMPLEX` object 10397 10398 Output Parameters: 10399 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10400 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10401 10402 Level: intermediate 10403 10404 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10405 @*/ 10406 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10407 { 10408 DM_Plex *plex = (DM_Plex *)dm->data; 10409 10410 PetscFunctionBegin; 10411 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10412 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10413 if (anchorSection) *anchorSection = plex->anchorSection; 10414 if (anchorIS) *anchorIS = plex->anchorIS; 10415 PetscFunctionReturn(PETSC_SUCCESS); 10416 } 10417 10418 /*@ 10419 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10420 10421 Collective 10422 10423 Input Parameters: 10424 + dm - The `DMPLEX` object 10425 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10426 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10427 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10428 10429 Level: intermediate 10430 10431 Notes: 10432 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10433 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10434 combination of other points' degrees of freedom. 10435 10436 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10437 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10438 10439 The reference counts of `anchorSection` and `anchorIS` are incremented. 10440 10441 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10442 @*/ 10443 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10444 { 10445 DM_Plex *plex = (DM_Plex *)dm->data; 10446 PetscMPIInt result; 10447 10448 PetscFunctionBegin; 10449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10450 if (anchorSection) { 10451 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10452 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10453 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10454 } 10455 if (anchorIS) { 10456 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10457 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10458 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10459 } 10460 10461 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10462 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10463 plex->anchorSection = anchorSection; 10464 10465 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10466 PetscCall(ISDestroy(&plex->anchorIS)); 10467 plex->anchorIS = anchorIS; 10468 10469 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10470 PetscInt size, a, pStart, pEnd; 10471 const PetscInt *anchors; 10472 10473 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10474 PetscCall(ISGetLocalSize(anchorIS, &size)); 10475 PetscCall(ISGetIndices(anchorIS, &anchors)); 10476 for (a = 0; a < size; a++) { 10477 PetscInt p; 10478 10479 p = anchors[a]; 10480 if (p >= pStart && p < pEnd) { 10481 PetscInt dof; 10482 10483 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10484 if (dof) { 10485 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10486 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10487 } 10488 } 10489 } 10490 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10491 } 10492 /* reset the generic constraints */ 10493 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10494 PetscFunctionReturn(PETSC_SUCCESS); 10495 } 10496 10497 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10498 { 10499 PetscSection anchorSection; 10500 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10501 10502 PetscFunctionBegin; 10503 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10504 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10505 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10506 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10507 if (numFields) { 10508 PetscInt f; 10509 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10510 10511 for (f = 0; f < numFields; f++) { 10512 PetscInt numComp; 10513 10514 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10515 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10516 } 10517 } 10518 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10519 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10520 pStart = PetscMax(pStart, sStart); 10521 pEnd = PetscMin(pEnd, sEnd); 10522 pEnd = PetscMax(pStart, pEnd); 10523 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10524 for (p = pStart; p < pEnd; p++) { 10525 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10526 if (dof) { 10527 PetscCall(PetscSectionGetDof(section, p, &dof)); 10528 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10529 for (f = 0; f < numFields; f++) { 10530 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10531 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10532 } 10533 } 10534 } 10535 PetscCall(PetscSectionSetUp(*cSec)); 10536 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10537 PetscFunctionReturn(PETSC_SUCCESS); 10538 } 10539 10540 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10541 { 10542 PetscSection aSec; 10543 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10544 const PetscInt *anchors; 10545 PetscInt numFields, f; 10546 IS aIS; 10547 MatType mtype; 10548 PetscBool iscuda, iskokkos; 10549 10550 PetscFunctionBegin; 10551 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10552 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10553 PetscCall(PetscSectionGetStorageSize(section, &n)); 10554 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10555 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10556 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10557 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10558 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10559 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10560 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10561 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10562 else mtype = MATSEQAIJ; 10563 PetscCall(MatSetType(*cMat, mtype)); 10564 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10565 PetscCall(ISGetIndices(aIS, &anchors)); 10566 /* cSec will be a subset of aSec and section */ 10567 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10568 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10569 PetscCall(PetscMalloc1(m + 1, &i)); 10570 i[0] = 0; 10571 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10572 for (p = pStart; p < pEnd; p++) { 10573 PetscInt rDof, rOff, r; 10574 10575 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10576 if (!rDof) continue; 10577 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10578 if (numFields) { 10579 for (f = 0; f < numFields; f++) { 10580 annz = 0; 10581 for (r = 0; r < rDof; r++) { 10582 a = anchors[rOff + r]; 10583 if (a < sStart || a >= sEnd) continue; 10584 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10585 annz += aDof; 10586 } 10587 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10588 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10589 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10590 } 10591 } else { 10592 annz = 0; 10593 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10594 for (q = 0; q < dof; q++) { 10595 a = anchors[rOff + q]; 10596 if (a < sStart || a >= sEnd) continue; 10597 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10598 annz += aDof; 10599 } 10600 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10601 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10602 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10603 } 10604 } 10605 nnz = i[m]; 10606 PetscCall(PetscMalloc1(nnz, &j)); 10607 offset = 0; 10608 for (p = pStart; p < pEnd; p++) { 10609 if (numFields) { 10610 for (f = 0; f < numFields; f++) { 10611 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10612 for (q = 0; q < dof; q++) { 10613 PetscInt rDof, rOff, r; 10614 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10615 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10616 for (r = 0; r < rDof; r++) { 10617 PetscInt s; 10618 10619 a = anchors[rOff + r]; 10620 if (a < sStart || a >= sEnd) continue; 10621 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10622 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10623 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10624 } 10625 } 10626 } 10627 } else { 10628 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10629 for (q = 0; q < dof; q++) { 10630 PetscInt rDof, rOff, r; 10631 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10632 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10633 for (r = 0; r < rDof; r++) { 10634 PetscInt s; 10635 10636 a = anchors[rOff + r]; 10637 if (a < sStart || a >= sEnd) continue; 10638 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10639 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10640 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10641 } 10642 } 10643 } 10644 } 10645 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10646 PetscCall(PetscFree(i)); 10647 PetscCall(PetscFree(j)); 10648 PetscCall(ISRestoreIndices(aIS, &anchors)); 10649 PetscFunctionReturn(PETSC_SUCCESS); 10650 } 10651 10652 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10653 { 10654 DM_Plex *plex = (DM_Plex *)dm->data; 10655 PetscSection anchorSection, section, cSec; 10656 Mat cMat; 10657 10658 PetscFunctionBegin; 10659 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10660 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10661 if (anchorSection) { 10662 PetscInt Nf; 10663 10664 PetscCall(DMGetLocalSection(dm, §ion)); 10665 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10666 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10667 PetscCall(DMGetNumFields(dm, &Nf)); 10668 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10669 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10670 PetscCall(PetscSectionDestroy(&cSec)); 10671 PetscCall(MatDestroy(&cMat)); 10672 } 10673 PetscFunctionReturn(PETSC_SUCCESS); 10674 } 10675 10676 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10677 { 10678 IS subis; 10679 PetscSection section, subsection; 10680 10681 PetscFunctionBegin; 10682 PetscCall(DMGetLocalSection(dm, §ion)); 10683 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10684 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10685 /* Create subdomain */ 10686 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10687 /* Create submodel */ 10688 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10689 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10690 PetscCall(DMSetLocalSection(*subdm, subsection)); 10691 PetscCall(PetscSectionDestroy(&subsection)); 10692 PetscCall(DMCopyDisc(dm, *subdm)); 10693 /* Create map from submodel to global model */ 10694 if (is) { 10695 PetscSection sectionGlobal, subsectionGlobal; 10696 IS spIS; 10697 const PetscInt *spmap; 10698 PetscInt *subIndices; 10699 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10700 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10701 10702 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10703 PetscCall(ISGetIndices(spIS, &spmap)); 10704 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10705 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10706 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10707 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10708 for (p = pStart; p < pEnd; ++p) { 10709 PetscInt gdof, pSubSize = 0; 10710 10711 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10712 if (gdof > 0) { 10713 for (f = 0; f < Nf; ++f) { 10714 PetscInt fdof, fcdof; 10715 10716 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10717 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10718 pSubSize += fdof - fcdof; 10719 } 10720 subSize += pSubSize; 10721 if (pSubSize) { 10722 if (bs < 0) { 10723 bs = pSubSize; 10724 } else if (bs != pSubSize) { 10725 /* Layout does not admit a pointwise block size */ 10726 bs = 1; 10727 } 10728 } 10729 } 10730 } 10731 /* Must have same blocksize on all procs (some might have no points) */ 10732 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10733 bsLocal[1] = bs; 10734 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10735 if (bsMinMax[0] != bsMinMax[1]) { 10736 bs = 1; 10737 } else { 10738 bs = bsMinMax[0]; 10739 } 10740 PetscCall(PetscMalloc1(subSize, &subIndices)); 10741 for (p = pStart; p < pEnd; ++p) { 10742 PetscInt gdof, goff; 10743 10744 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10745 if (gdof > 0) { 10746 const PetscInt point = spmap[p]; 10747 10748 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10749 for (f = 0; f < Nf; ++f) { 10750 PetscInt fdof, fcdof, fc, f2, poff = 0; 10751 10752 /* Can get rid of this loop by storing field information in the global section */ 10753 for (f2 = 0; f2 < f; ++f2) { 10754 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10755 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10756 poff += fdof - fcdof; 10757 } 10758 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10759 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10760 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10761 } 10762 } 10763 } 10764 PetscCall(ISRestoreIndices(spIS, &spmap)); 10765 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10766 if (bs > 1) { 10767 /* We need to check that the block size does not come from non-contiguous fields */ 10768 PetscInt i, j, set = 1; 10769 for (i = 0; i < subSize; i += bs) { 10770 for (j = 0; j < bs; ++j) { 10771 if (subIndices[i + j] != subIndices[i] + j) { 10772 set = 0; 10773 break; 10774 } 10775 } 10776 } 10777 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10778 } 10779 /* Attach nullspace */ 10780 for (f = 0; f < Nf; ++f) { 10781 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10782 if ((*subdm)->nullspaceConstructors[f]) break; 10783 } 10784 if (f < Nf) { 10785 MatNullSpace nullSpace; 10786 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10787 10788 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10789 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10790 } 10791 } 10792 PetscFunctionReturn(PETSC_SUCCESS); 10793 } 10794 10795 /*@ 10796 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10797 10798 Input Parameters: 10799 + dm - The `DM` 10800 - dummy - unused argument 10801 10802 Options Database Key: 10803 . -dm_plex_monitor_throughput - Activate the monitor 10804 10805 Level: developer 10806 10807 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10808 @*/ 10809 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10810 { 10811 PetscLogHandler default_handler; 10812 10813 PetscFunctionBegin; 10814 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10815 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10816 if (default_handler) { 10817 PetscLogEvent event; 10818 PetscEventPerfInfo eventInfo; 10819 PetscLogDouble cellRate, flopRate; 10820 PetscInt cStart, cEnd, Nf, N; 10821 const char *name; 10822 10823 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10824 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10825 PetscCall(DMGetNumFields(dm, &Nf)); 10826 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10827 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10828 N = (cEnd - cStart) * Nf * eventInfo.count; 10829 flopRate = eventInfo.flops / eventInfo.time; 10830 cellRate = N / eventInfo.time; 10831 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)); 10832 } else { 10833 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."); 10834 } 10835 PetscFunctionReturn(PETSC_SUCCESS); 10836 } 10837