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 /* Logging support */ 18 PetscLogEvent DMPLEX_DistributionView, DMPLEX_DistributionLoad; 19 20 PetscBool Plexcite = PETSC_FALSE; 21 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 22 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 23 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 24 "journal = {SIAM Journal on Scientific Computing},\n" 25 "volume = {38},\n" 26 "number = {5},\n" 27 "pages = {S143--S155},\n" 28 "eprint = {http://arxiv.org/abs/1506.07749},\n" 29 "doi = {10.1137/15M1026092},\n" 30 "year = {2016},\n" 31 "petsc_uses={DMPlex},\n}\n"; 32 33 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 34 35 /*@ 36 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 37 38 Input Parameter: 39 . dm - The `DMPLEX` object 40 41 Output Parameter: 42 . simplex - Flag checking for a simplex 43 44 Level: intermediate 45 46 Note: 47 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 48 If the mesh has no cells, this returns `PETSC_FALSE`. 49 50 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 51 @*/ 52 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 53 { 54 DMPolytopeType ct; 55 PetscInt cStart, cEnd; 56 57 PetscFunctionBegin; 58 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 59 if (cEnd <= cStart) { 60 *simplex = PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 64 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 65 PetscFunctionReturn(PETSC_SUCCESS); 66 } 67 68 /*@ 69 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 70 71 Input Parameters: 72 + dm - The `DMPLEX` object 73 - height - The cell height in the Plex, 0 is the default 74 75 Output Parameters: 76 + cStart - The first "normal" cell, pass `NULL` if not needed 77 - cEnd - The upper bound on "normal" cells, pass `NULL` if not needed 78 79 Level: developer 80 81 Note: 82 This function requires that tensor cells are ordered last. 83 84 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 85 @*/ 86 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PeOp PetscInt *cStart, PeOp PetscInt *cEnd) 87 { 88 DMLabel ctLabel; 89 IS valueIS; 90 const PetscInt *ctypes; 91 PetscBool found = PETSC_FALSE; 92 PetscInt Nct, cS = PETSC_INT_MAX, cE = 0; 93 94 PetscFunctionBegin; 95 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 96 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 97 PetscCall(ISGetLocalSize(valueIS, &Nct)); 98 PetscCall(ISGetIndices(valueIS, &ctypes)); 99 for (PetscInt t = 0; t < Nct; ++t) { 100 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 101 PetscInt ctS, ctE, ht; 102 103 if (ct == DM_POLYTOPE_UNKNOWN) { 104 // If any cells are not typed, just use all cells 105 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 106 break; 107 } 108 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 109 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 110 if (ctS >= ctE) continue; 111 // Check that a point has the right height 112 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 113 if (ht != height) continue; 114 cS = PetscMin(cS, ctS); 115 cE = PetscMax(cE, ctE); 116 found = PETSC_TRUE; 117 } 118 if (!Nct || !found) cS = cE = 0; 119 PetscCall(ISDestroy(&valueIS)); 120 // Reset label for fast lookup 121 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 122 if (cStart) *cStart = cS; 123 if (cEnd) *cEnd = cE; 124 PetscFunctionReturn(PETSC_SUCCESS); 125 } 126 127 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 128 { 129 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 130 PetscInt *sStart, *sEnd; 131 PetscViewerVTKFieldType *ft; 132 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 133 DMLabel depthLabel, ctLabel; 134 135 PetscFunctionBegin; 136 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 137 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 138 PetscCall(DMGetCoordinateDim(dm, &cdim)); 139 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 140 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 141 if (field >= 0) { 142 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 143 } else { 144 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 145 } 146 147 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 148 PetscCall(DMPlexGetDepth(dm, &depth)); 149 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 150 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 151 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 152 const DMPolytopeType ict = (DMPolytopeType)c; 153 PetscInt dep; 154 155 if (ict == DM_POLYTOPE_FV_GHOST) continue; 156 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 157 if (pStart >= 0) { 158 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 159 if (dep != depth - cellHeight) continue; 160 } 161 if (field >= 0) { 162 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 163 } else { 164 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 165 } 166 } 167 168 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 169 *types = 0; 170 171 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 172 if (globalvcdof[c]) ++(*types); 173 } 174 175 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 176 t = 0; 177 if (globalvcdof[DM_NUM_POLYTOPES]) { 178 sStart[t] = vStart; 179 sEnd[t] = vEnd; 180 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 181 ++t; 182 } 183 184 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 185 if (globalvcdof[c]) { 186 const DMPolytopeType ict = (DMPolytopeType)c; 187 188 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 189 sStart[t] = cStart; 190 sEnd[t] = cEnd; 191 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 192 ++t; 193 } 194 } 195 196 if (!*types) { 197 if (field >= 0) { 198 const char *fieldname; 199 200 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 201 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 202 } else { 203 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 204 } 205 } 206 207 *ssStart = sStart; 208 *ssEnd = sEnd; 209 *sft = ft; 210 PetscFunctionReturn(PETSC_SUCCESS); 211 } 212 213 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 214 { 215 PetscFunctionBegin; 216 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 217 PetscFunctionReturn(PETSC_SUCCESS); 218 } 219 220 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 221 { 222 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 223 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 224 225 PetscFunctionBegin; 226 *ft = PETSC_VTK_INVALID; 227 PetscCall(DMGetCoordinateDim(dm, &cdim)); 228 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 229 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 230 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 231 if (field >= 0) { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 234 } else { 235 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 236 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 237 } 238 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 239 if (globalvcdof[0]) { 240 *sStart = vStart; 241 *sEnd = vEnd; 242 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 243 else *ft = PETSC_VTK_POINT_FIELD; 244 } else if (globalvcdof[1]) { 245 *sStart = cStart; 246 *sEnd = cEnd; 247 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 248 else *ft = PETSC_VTK_CELL_FIELD; 249 } else { 250 if (field >= 0) { 251 const char *fieldname; 252 253 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 254 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 255 } else { 256 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n")); 257 } 258 } 259 PetscFunctionReturn(PETSC_SUCCESS); 260 } 261 262 /*@ 263 DMPlexVecView1D - Plot many 1D solutions on the same line graph 264 265 Collective 266 267 Input Parameters: 268 + dm - The `DMPLEX` object 269 . n - The number of vectors 270 . u - The array of local vectors 271 - viewer - The `PetscViewer` 272 273 Level: advanced 274 275 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 276 @*/ 277 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 278 { 279 DM cdm; 280 PetscDS ds; 281 PetscDraw draw = NULL; 282 PetscDrawLG lg; 283 Vec coordinates; 284 const PetscScalar *coords, **sol; 285 PetscReal *vals; 286 PetscInt *Nc; 287 PetscInt Nf, Nl, vStart, vEnd, eStart, eEnd; 288 char **names; 289 290 PetscFunctionBegin; 291 PetscCall(DMGetCoordinateDM(dm, &cdm)); 292 PetscCall(DMGetDS(dm, &ds)); 293 PetscCall(PetscDSGetNumFields(ds, &Nf)); 294 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 295 PetscCall(PetscDSGetComponents(ds, &Nc)); 296 297 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 298 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 299 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 300 301 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 302 for (PetscInt i = 0, l = 0; i < n; ++i) { 303 const char *vname; 304 305 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 306 for (PetscInt f = 0; f < Nf; ++f) { 307 PetscObject disc; 308 const char *fname; 309 char tmpname[PETSC_MAX_PATH_LEN]; 310 311 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 312 /* TODO Create names for components */ 313 for (PetscInt c = 0; c < Nc[f]; ++c, ++l) { 314 PetscCall(PetscObjectGetName(disc, &fname)); 315 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 316 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 317 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 318 PetscCall(PetscStrallocpy(tmpname, &names[l])); 319 } 320 } 321 } 322 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 323 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 324 PetscCall(VecGetArrayRead(coordinates, &coords)); 325 for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 326 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 327 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 328 PetscSection s; 329 PetscInt cdof, vdof; 330 331 PetscCall(DMGetLocalSection(dm, &s)); 332 PetscCall(PetscSectionGetDof(s, eStart, &cdof)); 333 PetscCall(PetscSectionGetDof(s, vStart, &vdof)); 334 if (cdof) { 335 if (vdof) { 336 // P_2 337 PetscInt vFirst = -1; 338 339 for (PetscInt e = eStart; e < eEnd; ++e) { 340 PetscScalar *xa, *xb, *svals; 341 const PetscInt *cone; 342 343 PetscCall(DMPlexGetCone(dm, e, &cone)); 344 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 345 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 346 if (e == eStart) vFirst = cone[0]; 347 for (PetscInt i = 0; i < n; ++i) { 348 PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals)); 349 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 350 } 351 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals)); 352 if (e == eEnd - 1 && cone[1] != vFirst) { 353 for (PetscInt i = 0; i < n; ++i) { 354 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 355 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 356 } 357 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 358 for (PetscInt i = 0; i < n; ++i) { 359 PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals)); 360 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 361 } 362 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals)); 363 } 364 } 365 } else { 366 // P_0 367 for (PetscInt e = eStart; e < eEnd; ++e) { 368 PetscScalar *xa, *xb, *svals; 369 const PetscInt *cone; 370 371 PetscCall(DMPlexGetCone(dm, e, &cone)); 372 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 373 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 374 for (PetscInt i = 0; i < n; ++i) { 375 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 376 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 377 } 378 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 379 } 380 } 381 } else if (vdof) { 382 // P_1 383 for (PetscInt v = vStart; v < vEnd; ++v) { 384 PetscScalar *x, *svals; 385 386 PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x)); 387 for (PetscInt i = 0; i < n; ++i) { 388 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 389 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 390 } 391 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 392 } 393 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Discretization not supported"); 394 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 395 for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 396 for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 397 PetscCall(PetscFree3(sol, names, vals)); 398 399 PetscCall(PetscDrawLGDraw(lg)); 400 PetscCall(PetscDrawLGDestroy(&lg)); 401 PetscFunctionReturn(PETSC_SUCCESS); 402 } 403 404 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 405 { 406 DM dm; 407 408 PetscFunctionBegin; 409 PetscCall(VecGetDM(u, &dm)); 410 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 411 PetscFunctionReturn(PETSC_SUCCESS); 412 } 413 414 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 415 { 416 DM dm; 417 PetscSection s; 418 PetscDraw draw, popup; 419 DM cdm; 420 PetscSection coordSection; 421 Vec coordinates; 422 const PetscScalar *array; 423 PetscReal lbound[3], ubound[3]; 424 PetscReal vbound[2], time; 425 PetscBool flg; 426 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 427 const char *name; 428 char title[PETSC_MAX_PATH_LEN]; 429 430 PetscFunctionBegin; 431 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 432 PetscCall(VecGetDM(v, &dm)); 433 PetscCall(DMGetCoordinateDim(dm, &dim)); 434 PetscCall(DMGetLocalSection(dm, &s)); 435 PetscCall(PetscSectionGetNumFields(s, &Nf)); 436 PetscCall(DMGetCoarsenLevel(dm, &level)); 437 PetscCall(DMGetCoordinateDM(dm, &cdm)); 438 PetscCall(DMGetLocalSection(cdm, &coordSection)); 439 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 440 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 441 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 442 443 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 444 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 445 446 PetscCall(VecGetLocalSize(coordinates, &N)); 447 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 448 PetscCall(PetscDrawClear(draw)); 449 450 /* Could implement something like DMDASelectFields() */ 451 for (f = 0; f < Nf; ++f) { 452 DM fdm = dm; 453 Vec fv = v; 454 IS fis; 455 char prefix[PETSC_MAX_PATH_LEN]; 456 const char *fname; 457 458 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 459 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 460 461 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 462 else prefix[0] = '\0'; 463 if (Nf > 1) { 464 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 465 PetscCall(VecGetSubVector(v, fis, &fv)); 466 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 467 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 468 } 469 for (comp = 0; comp < Nc; ++comp, ++w) { 470 PetscInt nmax = 2; 471 472 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 473 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 474 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 475 PetscCall(PetscDrawSetTitle(draw, title)); 476 477 /* TODO Get max and min only for this component */ 478 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 479 if (!flg) { 480 PetscCall(VecMin(fv, NULL, &vbound[0])); 481 PetscCall(VecMax(fv, NULL, &vbound[1])); 482 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 483 } 484 485 PetscCall(PetscDrawGetPopup(draw, &popup)); 486 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 487 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 488 PetscCall(VecGetArrayRead(fv, &array)); 489 for (c = cStart; c < cEnd; ++c) { 490 DMPolytopeType ct; 491 PetscScalar *coords = NULL, *a = NULL; 492 const PetscScalar *coords_arr; 493 PetscBool isDG; 494 PetscInt numCoords; 495 int color[4] = {-1, -1, -1, -1}; 496 497 PetscCall(DMPlexGetCellType(dm, c, &ct)); 498 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 499 if (a) { 500 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 501 color[1] = color[2] = color[3] = color[0]; 502 } else { 503 PetscScalar *vals = NULL; 504 PetscInt numVals, va; 505 506 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 507 if (!numVals) { 508 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 509 continue; 510 } 511 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); 512 switch (numVals / Nc) { 513 case 1: /* P1 Clamped Segment Prism */ 514 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 515 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]); 516 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 517 break; 518 case 3: /* P1 Triangle */ 519 case 4: /* P1 Quadrangle */ 520 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]); 521 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 522 break; 523 case 6: /* P2 Triangle */ 524 case 8: /* P2 Quadrangle */ 525 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]); 526 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 527 break; 528 default: 529 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 530 } 531 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 532 } 533 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 534 switch (numCoords) { 535 case 6: 536 case 12: /* Localized triangle */ 537 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])); 538 break; 539 case 8: 540 case 16: /* Localized quadrilateral */ 541 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 542 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 543 } else { 544 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])); 545 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])); 546 } 547 break; 548 default: 549 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 550 } 551 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 552 } 553 PetscCall(VecRestoreArrayRead(fv, &array)); 554 PetscCall(PetscDrawFlush(draw)); 555 PetscCall(PetscDrawPause(draw)); 556 PetscCall(PetscDrawSave(draw)); 557 } 558 if (Nf > 1) { 559 PetscCall(VecRestoreSubVector(v, fis, &fv)); 560 PetscCall(ISDestroy(&fis)); 561 PetscCall(DMDestroy(&fdm)); 562 } 563 } 564 PetscFunctionReturn(PETSC_SUCCESS); 565 } 566 567 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 568 { 569 DM dm; 570 PetscDraw draw; 571 PetscInt dim; 572 PetscBool isnull; 573 574 PetscFunctionBegin; 575 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 576 PetscCall(PetscDrawIsNull(draw, &isnull)); 577 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 578 579 PetscCall(VecGetDM(v, &dm)); 580 PetscCall(DMGetCoordinateDim(dm, &dim)); 581 switch (dim) { 582 case 1: 583 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 584 break; 585 case 2: 586 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 587 break; 588 default: 589 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 590 } 591 PetscFunctionReturn(PETSC_SUCCESS); 592 } 593 594 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 595 { 596 DM dm; 597 Vec locv; 598 const char *name; 599 PetscSection section; 600 PetscInt pStart, pEnd; 601 PetscInt numFields; 602 PetscViewerVTKFieldType ft; 603 604 PetscFunctionBegin; 605 PetscCall(VecGetDM(v, &dm)); 606 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 607 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 608 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 609 PetscCall(VecCopy(v, locv)); 610 PetscCall(DMGetLocalSection(dm, §ion)); 611 PetscCall(PetscSectionGetNumFields(section, &numFields)); 612 if (!numFields) { 613 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 614 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 615 } else { 616 PetscInt f; 617 618 for (f = 0; f < numFields; f++) { 619 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 620 if (ft == PETSC_VTK_INVALID) continue; 621 PetscCall(PetscObjectReference((PetscObject)locv)); 622 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 623 } 624 PetscCall(VecDestroy(&locv)); 625 } 626 PetscFunctionReturn(PETSC_SUCCESS); 627 } 628 629 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 630 { 631 DM dm; 632 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython; 633 634 PetscFunctionBegin; 635 PetscCall(VecGetDM(v, &dm)); 636 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 640 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 641 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 642 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 643 if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) { 644 PetscInt i, numFields; 645 PetscObject fe; 646 PetscBool fem = PETSC_FALSE; 647 Vec locv = v; 648 const char *name; 649 PetscInt step; 650 PetscReal time; 651 652 PetscCall(DMGetNumFields(dm, &numFields)); 653 for (i = 0; i < numFields; i++) { 654 PetscCall(DMGetField(dm, i, NULL, &fe)); 655 if (fe->classid == PETSCFE_CLASSID) { 656 fem = PETSC_TRUE; 657 break; 658 } 659 } 660 if (fem) { 661 PetscObject isZero; 662 663 PetscCall(DMGetLocalVector(dm, &locv)); 664 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 665 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 666 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 667 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 668 PetscCall(VecCopy(v, locv)); 669 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 670 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 671 } 672 if (isvtk) { 673 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 674 } else if (ishdf5) { 675 #if defined(PETSC_HAVE_HDF5) 676 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 677 #else 678 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 679 #endif 680 } else if (isdraw) { 681 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 682 } else if (ispython) { 683 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv)); 684 } else if (isglvis) { 685 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 686 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 687 PetscCall(VecView_GLVis(locv, viewer)); 688 } else if (iscgns) { 689 #if defined(PETSC_HAVE_CGNS) 690 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 691 #else 692 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 693 #endif 694 } 695 if (fem) { 696 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 697 PetscCall(DMRestoreLocalVector(dm, &locv)); 698 } 699 } else { 700 PetscBool isseq; 701 702 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 703 if (isseq) PetscCall(VecView_Seq(v, viewer)); 704 else PetscCall(VecView_MPI(v, viewer)); 705 } 706 PetscFunctionReturn(PETSC_SUCCESS); 707 } 708 709 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 710 { 711 DM dm; 712 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython; 713 714 PetscFunctionBegin; 715 PetscCall(VecGetDM(v, &dm)); 716 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 721 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 722 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 723 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 724 if (isvtk || isdraw || isglvis || iscgns || ispython) { 725 Vec locv; 726 PetscObject isZero; 727 const char *name; 728 729 PetscCall(DMGetLocalVector(dm, &locv)); 730 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 731 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 732 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 733 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 734 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 735 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 736 PetscCall(VecView_Plex_Local(locv, viewer)); 737 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 738 PetscCall(DMRestoreLocalVector(dm, &locv)); 739 } else if (ishdf5) { 740 #if defined(PETSC_HAVE_HDF5) 741 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 742 #else 743 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 744 #endif 745 } else if (isexodusii) { 746 #if defined(PETSC_HAVE_EXODUSII) 747 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 748 #else 749 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 750 #endif 751 } else { 752 PetscBool isseq; 753 754 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 755 if (isseq) PetscCall(VecView_Seq(v, viewer)); 756 else PetscCall(VecView_MPI(v, viewer)); 757 } 758 PetscFunctionReturn(PETSC_SUCCESS); 759 } 760 761 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 762 { 763 DM dm; 764 MPI_Comm comm; 765 PetscViewerFormat format; 766 Vec v; 767 PetscBool isvtk, ishdf5; 768 769 PetscFunctionBegin; 770 PetscCall(VecGetDM(originalv, &dm)); 771 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 772 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 773 PetscCall(PetscViewerGetFormat(viewer, &format)); 774 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 775 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 776 if (format == PETSC_VIEWER_NATIVE) { 777 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 778 /* this need a better fix */ 779 if (dm->useNatural) { 780 if (dm->sfNatural) { 781 const char *vecname; 782 PetscInt n, nroots; 783 784 PetscCall(VecGetLocalSize(originalv, &n)); 785 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 786 if (n == nroots) { 787 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 788 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 789 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 790 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 791 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 792 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 793 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 794 } else v = originalv; 795 } else v = originalv; 796 797 if (ishdf5) { 798 #if defined(PETSC_HAVE_HDF5) 799 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 800 #else 801 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 802 #endif 803 } else if (isvtk) { 804 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 805 } else { 806 PetscBool isseq; 807 808 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 809 if (isseq) PetscCall(VecView_Seq(v, viewer)); 810 else PetscCall(VecView_MPI(v, viewer)); 811 } 812 if (v != originalv) PetscCall(VecDestroy(&v)); 813 PetscFunctionReturn(PETSC_SUCCESS); 814 } 815 816 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 817 { 818 DM dm; 819 PetscBool ishdf5; 820 821 PetscFunctionBegin; 822 PetscCall(VecGetDM(v, &dm)); 823 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 824 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 825 if (ishdf5) { 826 DM dmBC; 827 Vec gv; 828 const char *name; 829 830 PetscCall(DMGetOutputDM(dm, &dmBC)); 831 PetscCall(DMGetGlobalVector(dmBC, &gv)); 832 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 833 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 834 PetscCall(VecLoad_Default(gv, viewer)); 835 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 836 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 837 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 838 } else PetscCall(VecLoad_Default(v, viewer)); 839 PetscFunctionReturn(PETSC_SUCCESS); 840 } 841 842 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 843 { 844 DM dm; 845 PetscBool ishdf5, isexodusii, iscgns; 846 847 PetscFunctionBegin; 848 PetscCall(VecGetDM(v, &dm)); 849 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 850 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 851 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 852 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 853 if (ishdf5) { 854 #if defined(PETSC_HAVE_HDF5) 855 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 856 #else 857 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 858 #endif 859 } else if (isexodusii) { 860 #if defined(PETSC_HAVE_EXODUSII) 861 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 862 #else 863 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 864 #endif 865 } else if (iscgns) { 866 #if defined(PETSC_HAVE_CGNS) 867 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 868 #else 869 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 870 #endif 871 } else PetscCall(VecLoad_Default(v, viewer)); 872 PetscFunctionReturn(PETSC_SUCCESS); 873 } 874 875 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 876 { 877 DM dm; 878 PetscViewerFormat format; 879 PetscBool ishdf5; 880 881 PetscFunctionBegin; 882 PetscCall(VecGetDM(originalv, &dm)); 883 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 884 PetscCall(PetscViewerGetFormat(viewer, &format)); 885 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 886 if (format == PETSC_VIEWER_NATIVE) { 887 if (dm->useNatural) { 888 if (dm->sfNatural) { 889 if (ishdf5) { 890 #if defined(PETSC_HAVE_HDF5) 891 Vec v; 892 const char *vecname; 893 894 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 895 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 896 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 897 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 898 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 899 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 900 PetscCall(VecDestroy(&v)); 901 #else 902 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 903 #endif 904 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 905 } 906 } else PetscCall(VecLoad_Default(originalv, viewer)); 907 } 908 PetscFunctionReturn(PETSC_SUCCESS); 909 } 910 911 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 912 { 913 PetscSection coordSection; 914 Vec coordinates; 915 DMLabel depthLabel, celltypeLabel; 916 const char *name[4]; 917 const PetscScalar *a; 918 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 919 920 PetscFunctionBegin; 921 PetscCall(DMGetDimension(dm, &dim)); 922 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 923 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 924 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 925 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 926 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 927 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 928 PetscCall(VecGetArrayRead(coordinates, &a)); 929 name[0] = "vertex"; 930 name[1] = "edge"; 931 name[dim - 1] = "face"; 932 name[dim] = "cell"; 933 for (c = cStart; c < cEnd; ++c) { 934 PetscInt *closure = NULL; 935 PetscInt closureSize, cl, ct; 936 937 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 938 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 939 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 940 PetscCall(PetscViewerASCIIPushTab(viewer)); 941 for (cl = 0; cl < closureSize * 2; cl += 2) { 942 PetscInt point = closure[cl], depth, dof, off, d, p; 943 944 if ((point < pStart) || (point >= pEnd)) continue; 945 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 946 if (!dof) continue; 947 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 948 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 949 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 950 for (p = 0; p < dof / dim; ++p) { 951 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 952 for (d = 0; d < dim; ++d) { 953 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 955 } 956 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 957 } 958 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 959 } 960 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 961 PetscCall(PetscViewerASCIIPopTab(viewer)); 962 } 963 PetscCall(VecRestoreArrayRead(coordinates, &a)); 964 PetscFunctionReturn(PETSC_SUCCESS); 965 } 966 967 typedef enum { 968 CS_CARTESIAN, 969 CS_POLAR, 970 CS_CYLINDRICAL, 971 CS_SPHERICAL 972 } CoordSystem; 973 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 974 975 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 976 { 977 PetscInt i; 978 979 PetscFunctionBegin; 980 if (dim > 3) { 981 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 982 } else { 983 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 984 985 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 986 switch (cs) { 987 case CS_CARTESIAN: 988 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 989 break; 990 case CS_POLAR: 991 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 992 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 993 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 994 break; 995 case CS_CYLINDRICAL: 996 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 997 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 998 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 999 trcoords[2] = coords[2]; 1000 break; 1001 case CS_SPHERICAL: 1002 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 1003 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 1004 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 1005 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 1006 break; 1007 } 1008 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 1009 } 1010 PetscFunctionReturn(PETSC_SUCCESS); 1011 } 1012 1013 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 1014 { 1015 DM_Plex *mesh = (DM_Plex *)dm->data; 1016 DM cdm, cdmCell; 1017 PetscSection coordSection, coordSectionCell; 1018 Vec coordinates, coordinatesCell; 1019 PetscViewerFormat format; 1020 1021 PetscFunctionBegin; 1022 PetscCall(PetscViewerGetFormat(viewer, &format)); 1023 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1024 const char *name; 1025 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1026 PetscInt pStart, pEnd, p, numLabels, l; 1027 PetscMPIInt rank, size; 1028 1029 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1030 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1031 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1032 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1033 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1034 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1035 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1036 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1037 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1038 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1039 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1040 PetscCall(DMGetDimension(dm, &dim)); 1041 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1042 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1043 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1044 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1045 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1046 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1047 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1048 for (p = pStart; p < pEnd; ++p) { 1049 PetscInt dof, off, s; 1050 1051 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1052 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1053 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1054 } 1055 PetscCall(PetscViewerFlush(viewer)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1057 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1058 for (p = pStart; p < pEnd; ++p) { 1059 PetscInt dof, off, c; 1060 1061 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1062 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1063 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])); 1064 } 1065 PetscCall(PetscViewerFlush(viewer)); 1066 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1067 if (coordSection && coordinates) { 1068 CoordSystem cs = CS_CARTESIAN; 1069 const PetscScalar *array, *arrayCell = NULL; 1070 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1071 PetscMPIInt rank; 1072 const char *name; 1073 1074 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1075 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1076 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1077 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1078 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1079 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1080 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1081 pStart = PetscMin(pvStart, pcStart); 1082 pEnd = PetscMax(pvEnd, pcEnd); 1083 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1084 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1085 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1086 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1087 1088 PetscCall(VecGetArrayRead(coordinates, &array)); 1089 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1090 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1091 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1092 for (p = pStart; p < pEnd; ++p) { 1093 PetscInt dof, off; 1094 1095 if (p >= pvStart && p < pvEnd) { 1096 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1097 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1098 if (dof) { 1099 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1100 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1101 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1102 } 1103 } 1104 if (cdmCell && p >= pcStart && p < pcEnd) { 1105 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1106 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1107 if (dof) { 1108 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1109 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1110 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1111 } 1112 } 1113 } 1114 PetscCall(PetscViewerFlush(viewer)); 1115 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1116 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1117 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1118 } 1119 PetscCall(DMGetNumLabels(dm, &numLabels)); 1120 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1121 for (l = 0; l < numLabels; ++l) { 1122 DMLabel label; 1123 PetscBool isdepth; 1124 const char *name; 1125 1126 PetscCall(DMGetLabelName(dm, l, &name)); 1127 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1128 if (isdepth) continue; 1129 PetscCall(DMGetLabel(dm, name, &label)); 1130 PetscCall(DMLabelView(label, viewer)); 1131 } 1132 if (size > 1) { 1133 PetscSF sf; 1134 1135 PetscCall(DMGetPointSF(dm, &sf)); 1136 PetscCall(PetscSFView(sf, viewer)); 1137 } 1138 if (mesh->periodic.face_sfs) 1139 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1140 PetscCall(PetscViewerFlush(viewer)); 1141 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1142 const char *name, *color; 1143 const char *defcolors[3] = {"gray", "orange", "green"}; 1144 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1145 char lname[PETSC_MAX_PATH_LEN]; 1146 PetscReal scale = 2.0; 1147 PetscReal tikzscale = 1.0; 1148 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1149 double tcoords[3]; 1150 PetscScalar *coords; 1151 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; 1152 PetscMPIInt rank, size; 1153 char **names, **colors, **lcolors; 1154 PetscBool flg, lflg; 1155 PetscBT wp = NULL; 1156 PetscInt pEnd, pStart; 1157 1158 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1159 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1160 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1161 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1162 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1163 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1164 PetscCall(DMGetDimension(dm, &dim)); 1165 PetscCall(DMPlexGetDepth(dm, &depth)); 1166 PetscCall(DMGetNumLabels(dm, &numLabels)); 1167 numLabels = PetscMax(numLabels, 10); 1168 numColors = 10; 1169 numLColors = 10; 1170 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1171 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1172 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1173 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1174 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1175 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1176 n = 4; 1177 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &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 n = 4; 1180 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1181 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1182 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1183 if (!useLabels) numLabels = 0; 1184 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1185 if (!useColors) { 1186 numColors = 3; 1187 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1188 } 1189 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1190 if (!useColors) { 1191 numLColors = 4; 1192 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1193 } 1194 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1195 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1196 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1197 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1198 if (depth < dim) plotEdges = PETSC_FALSE; 1199 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1200 1201 /* filter points with labelvalue != labeldefaultvalue */ 1202 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1203 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1204 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1205 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1206 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1207 if (lflg) { 1208 DMLabel lbl; 1209 1210 PetscCall(DMGetLabel(dm, lname, &lbl)); 1211 if (lbl) { 1212 PetscInt val, defval; 1213 1214 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1215 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1216 for (c = pStart; c < pEnd; c++) { 1217 PetscInt *closure = NULL; 1218 PetscInt closureSize; 1219 1220 PetscCall(DMLabelGetValue(lbl, c, &val)); 1221 if (val == defval) continue; 1222 1223 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1224 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1225 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1226 } 1227 } 1228 } 1229 1230 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1231 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1232 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1234 \\documentclass[tikz]{standalone}\n\n\ 1235 \\usepackage{pgflibraryshapes}\n\ 1236 \\usetikzlibrary{backgrounds}\n\ 1237 \\usetikzlibrary{arrows}\n\ 1238 \\begin{document}\n")); 1239 if (size > 1) { 1240 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1241 for (p = 0; p < size; ++p) { 1242 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1243 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1244 } 1245 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1246 } 1247 if (drawHasse) { 1248 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1249 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1258 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1264 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1265 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1266 } 1267 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1268 1269 /* Plot vertices */ 1270 PetscCall(VecGetArray(coordinates, &coords)); 1271 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1272 for (v = vStart; v < vEnd; ++v) { 1273 PetscInt off, dof, d; 1274 PetscBool isLabeled = PETSC_FALSE; 1275 1276 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1277 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1278 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1280 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1281 for (d = 0; d < dof; ++d) { 1282 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1283 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1284 } 1285 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1286 if (dim == 3) { 1287 PetscReal tmp = tcoords[1]; 1288 tcoords[1] = tcoords[2]; 1289 tcoords[2] = -tmp; 1290 } 1291 for (d = 0; d < dof; ++d) { 1292 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1293 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1294 } 1295 if (drawHasse) color = colors[0 % numColors]; 1296 else color = colors[rank % numColors]; 1297 for (l = 0; l < numLabels; ++l) { 1298 PetscInt val; 1299 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1300 if (val >= 0) { 1301 color = lcolors[l % numLColors]; 1302 isLabeled = PETSC_TRUE; 1303 break; 1304 } 1305 } 1306 if (drawNumbers[0]) { 1307 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1308 } else if (drawColors[0]) { 1309 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1310 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1311 } 1312 PetscCall(VecRestoreArray(coordinates, &coords)); 1313 PetscCall(PetscViewerFlush(viewer)); 1314 /* Plot edges */ 1315 if (plotEdges) { 1316 PetscCall(VecGetArray(coordinates, &coords)); 1317 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1318 for (e = eStart; e < eEnd; ++e) { 1319 const PetscInt *cone; 1320 PetscInt coneSize, offA, offB, dof, d; 1321 1322 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1323 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1324 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1325 PetscCall(DMPlexGetCone(dm, e, &cone)); 1326 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1327 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1328 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1329 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1330 for (d = 0; d < dof; ++d) { 1331 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1332 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1333 } 1334 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1335 if (dim == 3) { 1336 PetscReal tmp = tcoords[1]; 1337 tcoords[1] = tcoords[2]; 1338 tcoords[2] = -tmp; 1339 } 1340 for (d = 0; d < dof; ++d) { 1341 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1342 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1343 } 1344 if (drawHasse) color = colors[1 % numColors]; 1345 else color = colors[rank % numColors]; 1346 for (l = 0; l < numLabels; ++l) { 1347 PetscInt val; 1348 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1349 if (val >= 0) { 1350 color = lcolors[l % numLColors]; 1351 break; 1352 } 1353 } 1354 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1355 } 1356 PetscCall(VecRestoreArray(coordinates, &coords)); 1357 PetscCall(PetscViewerFlush(viewer)); 1358 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1359 } 1360 /* Plot cells */ 1361 if (dim == 3 || !drawNumbers[1]) { 1362 for (e = eStart; e < eEnd; ++e) { 1363 const PetscInt *cone; 1364 1365 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1366 color = colors[rank % numColors]; 1367 for (l = 0; l < numLabels; ++l) { 1368 PetscInt val; 1369 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1370 if (val >= 0) { 1371 color = lcolors[l % numLColors]; 1372 break; 1373 } 1374 } 1375 PetscCall(DMPlexGetCone(dm, e, &cone)); 1376 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1377 } 1378 } else { 1379 DMPolytopeType ct; 1380 1381 /* Drawing a 2D polygon */ 1382 for (c = cStart; c < cEnd; ++c) { 1383 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1384 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1385 if (DMPolytopeTypeIsHybrid(ct)) { 1386 const PetscInt *cone; 1387 PetscInt coneSize, e; 1388 1389 PetscCall(DMPlexGetCone(dm, c, &cone)); 1390 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1391 for (e = 0; e < coneSize; ++e) { 1392 const PetscInt *econe; 1393 1394 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1395 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)); 1396 } 1397 } else { 1398 PetscInt *closure = NULL; 1399 PetscInt closureSize, Nv = 0, v; 1400 1401 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1402 for (p = 0; p < closureSize * 2; p += 2) { 1403 const PetscInt point = closure[p]; 1404 1405 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1406 } 1407 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1408 for (v = 0; v <= Nv; ++v) { 1409 const PetscInt vertex = closure[v % Nv]; 1410 1411 if (v > 0) { 1412 if (plotEdges) { 1413 const PetscInt *edge; 1414 PetscInt endpoints[2], ne; 1415 1416 endpoints[0] = closure[v - 1]; 1417 endpoints[1] = vertex; 1418 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1419 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1420 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1421 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1422 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1423 } 1424 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1425 } 1426 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1427 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1428 } 1429 } 1430 } 1431 for (c = cStart; c < cEnd; ++c) { 1432 double ccoords[3] = {0.0, 0.0, 0.0}; 1433 PetscBool isLabeled = PETSC_FALSE; 1434 PetscScalar *cellCoords = NULL; 1435 const PetscScalar *array; 1436 PetscInt numCoords, cdim, d; 1437 PetscBool isDG; 1438 1439 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1440 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1441 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1442 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1443 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1444 for (p = 0; p < numCoords / cdim; ++p) { 1445 for (d = 0; d < cdim; ++d) { 1446 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1447 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1448 } 1449 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1450 if (cdim == 3) { 1451 PetscReal tmp = tcoords[1]; 1452 tcoords[1] = tcoords[2]; 1453 tcoords[2] = -tmp; 1454 } 1455 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1456 } 1457 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1458 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1459 for (d = 0; d < cdim; ++d) { 1460 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1461 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1462 } 1463 if (drawHasse) color = colors[depth % numColors]; 1464 else color = colors[rank % numColors]; 1465 for (l = 0; l < numLabels; ++l) { 1466 PetscInt val; 1467 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1468 if (val >= 0) { 1469 color = lcolors[l % numLColors]; 1470 isLabeled = PETSC_TRUE; 1471 break; 1472 } 1473 } 1474 if (drawNumbers[dim]) { 1475 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1476 } else if (drawColors[dim]) { 1477 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1478 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1479 } 1480 if (drawHasse) { 1481 int height = 0; 1482 1483 color = colors[depth % numColors]; 1484 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1485 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1486 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1487 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1489 1490 if (depth > 2) { 1491 color = colors[1 % numColors]; 1492 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1493 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1494 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1495 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1496 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1497 } 1498 1499 color = colors[1 % numColors]; 1500 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1502 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1503 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1504 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1505 1506 color = colors[0 % numColors]; 1507 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1510 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1511 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1512 1513 for (p = pStart; p < pEnd; ++p) { 1514 const PetscInt *cone; 1515 PetscInt coneSize, cp; 1516 1517 PetscCall(DMPlexGetCone(dm, p, &cone)); 1518 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1519 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1520 } 1521 } 1522 PetscCall(PetscViewerFlush(viewer)); 1523 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1524 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1525 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1526 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1527 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1528 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1529 PetscCall(PetscFree3(names, colors, lcolors)); 1530 PetscCall(PetscBTDestroy(&wp)); 1531 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1532 Vec cown, acown; 1533 VecScatter sct; 1534 ISLocalToGlobalMapping g2l; 1535 IS gid, acis; 1536 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1537 MPI_Group ggroup, ngroup; 1538 PetscScalar *array, nid; 1539 const PetscInt *idxs; 1540 PetscInt *idxs2, *start, *adjacency, *work; 1541 PetscInt64 lm[3], gm[3]; 1542 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1543 PetscMPIInt d1, d2, rank; 1544 1545 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1546 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1547 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1548 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1549 #endif 1550 if (ncomm != MPI_COMM_NULL) { 1551 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1552 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1553 d1 = 0; 1554 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1555 nid = d2; 1556 PetscCallMPI(MPI_Group_free(&ggroup)); 1557 PetscCallMPI(MPI_Group_free(&ngroup)); 1558 PetscCallMPI(MPI_Comm_free(&ncomm)); 1559 } else nid = 0.0; 1560 1561 /* Get connectivity */ 1562 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1563 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1564 1565 /* filter overlapped local cells */ 1566 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1567 PetscCall(ISGetIndices(gid, &idxs)); 1568 PetscCall(ISGetLocalSize(gid, &cum)); 1569 PetscCall(PetscMalloc1(cum, &idxs2)); 1570 for (c = cStart, cum = 0; c < cEnd; c++) { 1571 if (idxs[c - cStart] < 0) continue; 1572 idxs2[cum++] = idxs[c - cStart]; 1573 } 1574 PetscCall(ISRestoreIndices(gid, &idxs)); 1575 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1576 PetscCall(ISDestroy(&gid)); 1577 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1578 1579 /* support for node-aware cell locality */ 1580 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1581 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1582 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1583 PetscCall(VecGetArray(cown, &array)); 1584 for (c = 0; c < numVertices; c++) array[c] = nid; 1585 PetscCall(VecRestoreArray(cown, &array)); 1586 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1587 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1588 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1589 PetscCall(ISDestroy(&acis)); 1590 PetscCall(VecScatterDestroy(&sct)); 1591 PetscCall(VecDestroy(&cown)); 1592 1593 /* compute edgeCut */ 1594 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1595 PetscCall(PetscMalloc1(cum, &work)); 1596 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1597 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1598 PetscCall(ISDestroy(&gid)); 1599 PetscCall(VecGetArray(acown, &array)); 1600 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1601 PetscInt totl; 1602 1603 totl = start[c + 1] - start[c]; 1604 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1605 for (i = 0; i < totl; i++) { 1606 if (work[i] < 0) { 1607 ect += 1; 1608 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1609 } 1610 } 1611 } 1612 PetscCall(PetscFree(work)); 1613 PetscCall(VecRestoreArray(acown, &array)); 1614 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1615 lm[1] = -numVertices; 1616 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1617 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1618 lm[0] = ect; /* edgeCut */ 1619 lm[1] = ectn; /* node-aware edgeCut */ 1620 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1621 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1622 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1623 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1624 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1625 #else 1626 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1627 #endif 1628 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1629 PetscCall(PetscFree(start)); 1630 PetscCall(PetscFree(adjacency)); 1631 PetscCall(VecDestroy(&acown)); 1632 } else { 1633 const char *name; 1634 PetscInt *sizes, *hybsizes, *ghostsizes; 1635 PetscInt locDepth, depth, cellHeight, dim, d; 1636 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1637 PetscInt numLabels, l, maxSize = 17; 1638 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1639 MPI_Comm comm; 1640 PetscMPIInt size, rank; 1641 1642 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1643 PetscCallMPI(MPI_Comm_size(comm, &size)); 1644 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1645 PetscCall(DMGetDimension(dm, &dim)); 1646 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1647 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1648 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1649 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1650 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1651 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1652 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1653 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1654 gcNum = gcEnd - gcStart; 1655 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1656 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1657 for (d = 0; d <= depth; d++) { 1658 PetscInt Nc[2] = {0, 0}, ict; 1659 1660 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1661 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1662 ict = ct0; 1663 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1664 ct0 = (DMPolytopeType)ict; 1665 for (p = pStart; p < pEnd; ++p) { 1666 DMPolytopeType ct; 1667 1668 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1669 if (ct == ct0) ++Nc[0]; 1670 else ++Nc[1]; 1671 } 1672 if (size < maxSize) { 1673 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1674 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1675 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1676 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1677 for (p = 0; p < size; ++p) { 1678 if (rank == 0) { 1679 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1680 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1681 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1682 } 1683 } 1684 } else { 1685 PetscInt locMinMax[2]; 1686 1687 locMinMax[0] = Nc[0] + Nc[1]; 1688 locMinMax[1] = Nc[0] + Nc[1]; 1689 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1690 locMinMax[0] = Nc[1]; 1691 locMinMax[1] = Nc[1]; 1692 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1693 if (d == depth) { 1694 locMinMax[0] = gcNum; 1695 locMinMax[1] = gcNum; 1696 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1697 } 1698 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1699 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1700 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1701 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1702 } 1703 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1704 } 1705 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1706 { 1707 const PetscReal *maxCell; 1708 const PetscReal *L; 1709 PetscBool localized; 1710 1711 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1712 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1713 if (L || localized) { 1714 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1715 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1716 if (L) { 1717 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1718 for (d = 0; d < dim; ++d) { 1719 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1720 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1721 } 1722 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1723 } 1724 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1725 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1726 } 1727 } 1728 PetscCall(DMGetNumLabels(dm, &numLabels)); 1729 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1730 for (l = 0; l < numLabels; ++l) { 1731 DMLabel label; 1732 const char *name; 1733 PetscInt *values; 1734 PetscInt numValues, v; 1735 1736 PetscCall(DMGetLabelName(dm, l, &name)); 1737 PetscCall(DMGetLabel(dm, name, &label)); 1738 PetscCall(DMLabelGetNumValues(label, &numValues)); 1739 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1740 1741 { // Extract array of DMLabel values so it can be sorted 1742 IS is_values; 1743 const PetscInt *is_values_local = NULL; 1744 1745 PetscCall(DMLabelGetValueIS(label, &is_values)); 1746 PetscCall(ISGetIndices(is_values, &is_values_local)); 1747 PetscCall(PetscMalloc1(numValues, &values)); 1748 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1749 PetscCall(PetscSortInt(numValues, values)); 1750 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1751 PetscCall(ISDestroy(&is_values)); 1752 } 1753 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1754 for (v = 0; v < numValues; ++v) { 1755 PetscInt size; 1756 1757 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1758 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1759 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1760 } 1761 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1762 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1763 PetscCall(PetscFree(values)); 1764 } 1765 { 1766 char **labelNames; 1767 PetscInt Nl = numLabels; 1768 PetscBool flg; 1769 1770 PetscCall(PetscMalloc1(Nl, &labelNames)); 1771 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1772 for (l = 0; l < Nl; ++l) { 1773 DMLabel label; 1774 1775 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1776 if (flg) { 1777 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1778 PetscCall(DMLabelView(label, viewer)); 1779 } 1780 PetscCall(PetscFree(labelNames[l])); 1781 } 1782 PetscCall(PetscFree(labelNames)); 1783 } 1784 /* If no fields are specified, people do not want to see adjacency */ 1785 if (dm->Nf) { 1786 PetscInt f; 1787 1788 for (f = 0; f < dm->Nf; ++f) { 1789 const char *name; 1790 1791 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1792 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1793 PetscCall(PetscViewerASCIIPushTab(viewer)); 1794 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1795 if (dm->fields[f].adjacency[0]) { 1796 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1797 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1798 } else { 1799 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1800 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1801 } 1802 PetscCall(PetscViewerASCIIPopTab(viewer)); 1803 } 1804 } 1805 DMPlexTransform tr; 1806 1807 PetscCall(DMPlexGetTransform(dm, &tr)); 1808 if (tr) { 1809 PetscCall(PetscViewerASCIIPushTab(viewer)); 1810 PetscCall(PetscViewerASCIIPrintf(viewer, "Created using transform:\n")); 1811 PetscCall(DMPlexTransformView(tr, viewer)); 1812 PetscCall(PetscViewerASCIIPopTab(viewer)); 1813 } 1814 PetscCall(DMGetCoarseDM(dm, &cdm)); 1815 if (cdm) { 1816 PetscCall(PetscViewerASCIIPushTab(viewer)); 1817 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1818 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1819 PetscCall(PetscViewerASCIIPopTab(viewer)); 1820 } 1821 } 1822 PetscFunctionReturn(PETSC_SUCCESS); 1823 } 1824 1825 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt lineColor, PetscInt cellColor, PetscInt cell, const PetscScalar coords[]) 1826 { 1827 DMPolytopeType ct; 1828 PetscMPIInt rank; 1829 PetscInt cdim; 1830 1831 PetscFunctionBegin; 1832 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1833 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1834 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1835 lineColor = lineColor < 0 ? PETSC_DRAW_BLACK : lineColor; 1836 cellColor = cellColor < 0 ? PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2 : cellColor; 1837 switch (ct) { 1838 case DM_POLYTOPE_SEGMENT: 1839 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1840 switch (cdim) { 1841 case 1: { 1842 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1843 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1844 1845 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, lineColor)); 1846 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, lineColor)); 1847 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, lineColor)); 1848 } break; 1849 case 2: { 1850 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1851 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1852 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1853 1854 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1855 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, lineColor)); 1856 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, lineColor)); 1857 } break; 1858 default: 1859 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1860 } 1861 break; 1862 case DM_POLYTOPE_TRIANGLE: 1863 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1864 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1865 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1866 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1867 break; 1868 case DM_POLYTOPE_QUADRILATERAL: 1869 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1870 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), cellColor, cellColor, cellColor)); 1871 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1872 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1873 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor)); 1874 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1875 break; 1876 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1877 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1878 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1879 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1880 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor)); 1881 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1882 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1883 break; 1884 case DM_POLYTOPE_FV_GHOST: 1885 break; 1886 default: 1887 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1888 } 1889 PetscFunctionReturn(PETSC_SUCCESS); 1890 } 1891 1892 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1893 { 1894 PetscReal centroid[2] = {0., 0.}; 1895 PetscMPIInt rank; 1896 PetscMPIInt fillColor; 1897 1898 PetscFunctionBegin; 1899 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1900 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1901 for (PetscInt v = 0; v < Nv; ++v) { 1902 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1903 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1904 } 1905 for (PetscInt e = 0; e < Nv; ++e) { 1906 refCoords[0] = refVertices[e * 2 + 0]; 1907 refCoords[1] = refVertices[e * 2 + 1]; 1908 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1909 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1910 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1911 } 1912 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1913 for (PetscInt d = 0; d < edgeDiv; ++d) { 1914 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)); 1915 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1916 } 1917 } 1918 PetscFunctionReturn(PETSC_SUCCESS); 1919 } 1920 1921 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1922 { 1923 DMPolytopeType ct; 1924 1925 PetscFunctionBegin; 1926 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1927 switch (ct) { 1928 case DM_POLYTOPE_TRIANGLE: { 1929 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1930 1931 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1932 } break; 1933 case DM_POLYTOPE_QUADRILATERAL: { 1934 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1935 1936 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1937 } break; 1938 default: 1939 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1940 } 1941 PetscFunctionReturn(PETSC_SUCCESS); 1942 } 1943 1944 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1945 { 1946 PetscDraw draw; 1947 DM cdm; 1948 PetscSection coordSection; 1949 Vec coordinates; 1950 PetscReal xyl[3], xyr[3]; 1951 PetscReal *refCoords, *edgeCoords; 1952 PetscBool isnull, drawAffine; 1953 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv, lineColor = PETSC_DETERMINE, cellColor = PETSC_DETERMINE; 1954 1955 PetscFunctionBegin; 1956 PetscCall(DMGetCoordinateDim(dm, &dim)); 1957 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1958 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1959 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1960 edgeDiv = cDegree + 1; 1961 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_line_color", &lineColor, NULL)); 1962 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_cell_color", &cellColor, NULL)); 1963 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1964 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1965 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1966 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1967 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1968 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1969 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1970 1971 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1972 PetscCall(PetscDrawIsNull(draw, &isnull)); 1973 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1974 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1975 1976 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1977 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1978 PetscCall(PetscDrawClear(draw)); 1979 1980 for (c = cStart; c < cEnd; ++c) { 1981 PetscScalar *coords = NULL; 1982 const PetscScalar *coords_arr; 1983 PetscInt numCoords; 1984 PetscBool isDG; 1985 1986 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1987 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, lineColor, cellColor, c, coords)); 1988 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1989 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1990 } 1991 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1992 PetscCall(PetscDrawFlush(draw)); 1993 PetscCall(PetscDrawPause(draw)); 1994 PetscCall(PetscDrawSave(draw)); 1995 PetscFunctionReturn(PETSC_SUCCESS); 1996 } 1997 1998 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1999 { 2000 DM odm = dm, rdm = dm, cdm; 2001 PetscFE fe; 2002 PetscSpace sp; 2003 PetscClassId id; 2004 PetscInt degree; 2005 PetscBool hoView = PETSC_TRUE; 2006 2007 PetscFunctionBegin; 2008 PetscObjectOptionsBegin((PetscObject)dm); 2009 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 2010 PetscOptionsEnd(); 2011 PetscCall(PetscObjectReference((PetscObject)dm)); 2012 *hdm = dm; 2013 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 2014 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2015 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 2016 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 2017 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 2018 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 2019 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 2020 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 2021 DM cdm, rcdm; 2022 Mat In; 2023 Vec cl, rcl; 2024 2025 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 2026 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 2027 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 2028 PetscCall(DMGetCoordinateDM(odm, &cdm)); 2029 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 2030 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 2031 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 2032 PetscCall(DMSetCoarseDM(rcdm, cdm)); 2033 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 2034 PetscCall(MatMult(In, cl, rcl)); 2035 PetscCall(MatDestroy(&In)); 2036 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 2037 PetscCall(DMDestroy(&odm)); 2038 odm = rdm; 2039 } 2040 *hdm = rdm; 2041 PetscFunctionReturn(PETSC_SUCCESS); 2042 } 2043 2044 #if defined(PETSC_HAVE_EXODUSII) 2045 #include <exodusII.h> 2046 #include <petscviewerexodusii.h> 2047 #endif 2048 2049 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 2050 { 2051 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 2052 char name[PETSC_MAX_PATH_LEN]; 2053 2054 PetscFunctionBegin; 2055 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2056 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2057 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 2058 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2059 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2060 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2061 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 2062 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 2063 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 2064 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2065 if (iascii) { 2066 PetscViewerFormat format; 2067 PetscCall(PetscViewerGetFormat(viewer, &format)); 2068 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 2069 else PetscCall(DMPlexView_Ascii(dm, viewer)); 2070 } else if (ishdf5) { 2071 #if defined(PETSC_HAVE_HDF5) 2072 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 2073 #else 2074 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2075 #endif 2076 } else if (isvtk) { 2077 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2078 } else if (isdraw) { 2079 DM hdm; 2080 2081 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2082 PetscCall(DMPlexView_Draw(hdm, viewer)); 2083 PetscCall(DMDestroy(&hdm)); 2084 } else if (isglvis) { 2085 PetscCall(DMPlexView_GLVis(dm, viewer)); 2086 #if defined(PETSC_HAVE_EXODUSII) 2087 } else if (isexodus) { 2088 /* 2089 exodusII requires that all sets be part of exactly one cell set. 2090 If the dm does not have a "Cell Sets" label defined, we create one 2091 with ID 1, containing all cells. 2092 Note that if the Cell Sets label is defined but does not cover all cells, 2093 we may still have a problem. This should probably be checked here or in the viewer; 2094 */ 2095 PetscInt numCS; 2096 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2097 if (!numCS) { 2098 PetscInt cStart, cEnd, c; 2099 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2100 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2101 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2102 } 2103 PetscCall(DMView_PlexExodusII(dm, viewer)); 2104 #endif 2105 #if defined(PETSC_HAVE_CGNS) 2106 } else if (iscgns) { 2107 PetscCall(DMView_PlexCGNS(dm, viewer)); 2108 #endif 2109 } else if (ispython) { 2110 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2111 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2112 /* Optionally view the partition */ 2113 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2114 if (flg) { 2115 Vec ranks; 2116 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2117 PetscCall(VecView(ranks, viewer)); 2118 PetscCall(VecDestroy(&ranks)); 2119 } 2120 /* Optionally view a label */ 2121 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2122 if (flg) { 2123 DMLabel label; 2124 Vec val; 2125 2126 PetscCall(DMGetLabel(dm, name, &label)); 2127 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2128 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2129 PetscCall(VecView(val, viewer)); 2130 PetscCall(VecDestroy(&val)); 2131 } 2132 PetscFunctionReturn(PETSC_SUCCESS); 2133 } 2134 2135 /*@ 2136 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2137 2138 Collective 2139 2140 Input Parameters: 2141 + dm - The `DM` whose topology is to be saved 2142 - viewer - The `PetscViewer` to save it in 2143 2144 Level: advanced 2145 2146 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2147 @*/ 2148 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2149 { 2150 PetscBool ishdf5; 2151 2152 PetscFunctionBegin; 2153 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2154 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2155 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2156 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2157 if (ishdf5) { 2158 #if defined(PETSC_HAVE_HDF5) 2159 PetscViewerFormat format; 2160 PetscCall(PetscViewerGetFormat(viewer, &format)); 2161 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2162 IS globalPointNumbering; 2163 2164 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2165 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2166 PetscCall(ISDestroy(&globalPointNumbering)); 2167 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2168 #else 2169 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2170 #endif 2171 } 2172 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2173 PetscFunctionReturn(PETSC_SUCCESS); 2174 } 2175 2176 /*@ 2177 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2178 2179 Collective 2180 2181 Input Parameters: 2182 + dm - The `DM` whose coordinates are to be saved 2183 - viewer - The `PetscViewer` for saving 2184 2185 Level: advanced 2186 2187 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2188 @*/ 2189 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2190 { 2191 PetscBool ishdf5; 2192 2193 PetscFunctionBegin; 2194 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2195 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2196 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2197 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2198 if (ishdf5) { 2199 #if defined(PETSC_HAVE_HDF5) 2200 PetscViewerFormat format; 2201 PetscCall(PetscViewerGetFormat(viewer, &format)); 2202 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2203 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2204 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2205 #else 2206 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2207 #endif 2208 } 2209 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2210 PetscFunctionReturn(PETSC_SUCCESS); 2211 } 2212 2213 /*@ 2214 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2215 2216 Collective 2217 2218 Input Parameters: 2219 + dm - The `DM` whose labels are to be saved 2220 - viewer - The `PetscViewer` for saving 2221 2222 Level: advanced 2223 2224 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2225 @*/ 2226 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2227 { 2228 PetscBool ishdf5; 2229 2230 PetscFunctionBegin; 2231 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2232 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2233 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2234 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2235 if (ishdf5) { 2236 #if defined(PETSC_HAVE_HDF5) 2237 IS globalPointNumbering; 2238 PetscViewerFormat format; 2239 2240 PetscCall(PetscViewerGetFormat(viewer, &format)); 2241 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2242 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2243 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2244 PetscCall(ISDestroy(&globalPointNumbering)); 2245 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2246 #else 2247 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2248 #endif 2249 } 2250 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2251 PetscFunctionReturn(PETSC_SUCCESS); 2252 } 2253 2254 /*@ 2255 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2256 2257 Collective 2258 2259 Input Parameters: 2260 + dm - The `DM` that contains the topology on which the section to be saved is defined 2261 . viewer - The `PetscViewer` for saving 2262 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2263 2264 Level: advanced 2265 2266 Notes: 2267 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. 2268 2269 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. 2270 2271 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2272 @*/ 2273 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2274 { 2275 PetscBool ishdf5; 2276 2277 PetscFunctionBegin; 2278 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2279 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2280 if (!sectiondm) sectiondm = dm; 2281 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2282 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2283 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2284 if (ishdf5) { 2285 #if defined(PETSC_HAVE_HDF5) 2286 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2287 #else 2288 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2289 #endif 2290 } 2291 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2292 PetscFunctionReturn(PETSC_SUCCESS); 2293 } 2294 2295 /*@ 2296 DMPlexGlobalVectorView - Saves a global vector 2297 2298 Collective 2299 2300 Input Parameters: 2301 + dm - The `DM` that represents the topology 2302 . viewer - The `PetscViewer` to save data with 2303 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2304 - vec - The global vector to be saved 2305 2306 Level: advanced 2307 2308 Notes: 2309 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. 2310 2311 Calling sequence: 2312 .vb 2313 DMCreate(PETSC_COMM_WORLD, &dm); 2314 DMSetType(dm, DMPLEX); 2315 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2316 DMClone(dm, §iondm); 2317 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2318 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2319 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2320 PetscSectionSetChart(section, pStart, pEnd); 2321 PetscSectionSetUp(section); 2322 DMSetLocalSection(sectiondm, section); 2323 PetscSectionDestroy(§ion); 2324 DMGetGlobalVector(sectiondm, &vec); 2325 PetscObjectSetName((PetscObject)vec, "vec_name"); 2326 DMPlexTopologyView(dm, viewer); 2327 DMPlexSectionView(dm, viewer, sectiondm); 2328 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2329 DMRestoreGlobalVector(sectiondm, &vec); 2330 DMDestroy(§iondm); 2331 DMDestroy(&dm); 2332 .ve 2333 2334 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2335 @*/ 2336 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2337 { 2338 PetscBool ishdf5; 2339 2340 PetscFunctionBegin; 2341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2342 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2343 if (!sectiondm) sectiondm = dm; 2344 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2345 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2346 /* Check consistency */ 2347 { 2348 PetscSection section; 2349 PetscBool includesConstraints; 2350 PetscInt m, m1; 2351 2352 PetscCall(VecGetLocalSize(vec, &m1)); 2353 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2354 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2355 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2356 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2357 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2358 } 2359 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2360 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2361 if (ishdf5) { 2362 #if defined(PETSC_HAVE_HDF5) 2363 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2364 #else 2365 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2366 #endif 2367 } 2368 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2369 PetscFunctionReturn(PETSC_SUCCESS); 2370 } 2371 2372 /*@ 2373 DMPlexLocalVectorView - Saves a local vector 2374 2375 Collective 2376 2377 Input Parameters: 2378 + dm - The `DM` that represents the topology 2379 . viewer - The `PetscViewer` to save data with 2380 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2381 - vec - The local vector to be saved 2382 2383 Level: advanced 2384 2385 Note: 2386 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. 2387 2388 Calling sequence: 2389 .vb 2390 DMCreate(PETSC_COMM_WORLD, &dm); 2391 DMSetType(dm, DMPLEX); 2392 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2393 DMClone(dm, §iondm); 2394 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2395 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2396 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2397 PetscSectionSetChart(section, pStart, pEnd); 2398 PetscSectionSetUp(section); 2399 DMSetLocalSection(sectiondm, section); 2400 DMGetLocalVector(sectiondm, &vec); 2401 PetscObjectSetName((PetscObject)vec, "vec_name"); 2402 DMPlexTopologyView(dm, viewer); 2403 DMPlexSectionView(dm, viewer, sectiondm); 2404 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2405 DMRestoreLocalVector(sectiondm, &vec); 2406 DMDestroy(§iondm); 2407 DMDestroy(&dm); 2408 .ve 2409 2410 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2411 @*/ 2412 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2413 { 2414 PetscBool ishdf5; 2415 2416 PetscFunctionBegin; 2417 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2418 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2419 if (!sectiondm) sectiondm = dm; 2420 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2421 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2422 /* Check consistency */ 2423 { 2424 PetscSection section; 2425 PetscBool includesConstraints; 2426 PetscInt m, m1; 2427 2428 PetscCall(VecGetLocalSize(vec, &m1)); 2429 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2430 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2431 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2432 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2433 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2434 } 2435 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2436 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2437 if (ishdf5) { 2438 #if defined(PETSC_HAVE_HDF5) 2439 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2440 #else 2441 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2442 #endif 2443 } 2444 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2445 PetscFunctionReturn(PETSC_SUCCESS); 2446 } 2447 2448 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2449 { 2450 PetscBool ishdf5; 2451 2452 PetscFunctionBegin; 2453 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2454 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2455 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2456 if (ishdf5) { 2457 #if defined(PETSC_HAVE_HDF5) 2458 PetscViewerFormat format; 2459 PetscCall(PetscViewerGetFormat(viewer, &format)); 2460 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2461 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2462 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2463 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2464 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2465 PetscFunctionReturn(PETSC_SUCCESS); 2466 #else 2467 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2468 #endif 2469 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2470 } 2471 2472 /*@ 2473 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2474 2475 Collective 2476 2477 Input Parameters: 2478 + dm - The `DM` into which the topology is loaded 2479 - viewer - The `PetscViewer` for the saved topology 2480 2481 Output Parameter: 2482 . 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; 2483 `NULL` if unneeded 2484 2485 Level: advanced 2486 2487 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2488 `PetscViewer`, `PetscSF` 2489 @*/ 2490 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2491 { 2492 PetscBool ishdf5; 2493 2494 PetscFunctionBegin; 2495 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2496 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2497 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2498 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2499 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2500 if (ishdf5) { 2501 #if defined(PETSC_HAVE_HDF5) 2502 PetscViewerFormat format; 2503 PetscCall(PetscViewerGetFormat(viewer, &format)); 2504 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2505 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2506 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2507 #else 2508 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2509 #endif 2510 } 2511 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2512 PetscFunctionReturn(PETSC_SUCCESS); 2513 } 2514 2515 /*@ 2516 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2517 2518 Collective 2519 2520 Input Parameters: 2521 + dm - The `DM` into which the coordinates are loaded 2522 . viewer - The `PetscViewer` for the saved coordinates 2523 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2524 2525 Level: advanced 2526 2527 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2528 `PetscSF`, `PetscViewer` 2529 @*/ 2530 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2531 { 2532 PetscBool ishdf5; 2533 2534 PetscFunctionBegin; 2535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2536 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2537 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2538 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2539 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2540 if (ishdf5) { 2541 #if defined(PETSC_HAVE_HDF5) 2542 PetscViewerFormat format; 2543 PetscCall(PetscViewerGetFormat(viewer, &format)); 2544 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2545 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2546 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2547 #else 2548 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2549 #endif 2550 } 2551 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2552 PetscFunctionReturn(PETSC_SUCCESS); 2553 } 2554 2555 /*@ 2556 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2557 2558 Collective 2559 2560 Input Parameters: 2561 + dm - The `DM` into which the labels are loaded 2562 . viewer - The `PetscViewer` for the saved labels 2563 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2564 2565 Level: advanced 2566 2567 Note: 2568 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2569 2570 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2571 `PetscSF`, `PetscViewer` 2572 @*/ 2573 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2574 { 2575 PetscBool ishdf5; 2576 2577 PetscFunctionBegin; 2578 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2579 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2580 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2581 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2582 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2583 if (ishdf5) { 2584 #if defined(PETSC_HAVE_HDF5) 2585 PetscViewerFormat format; 2586 2587 PetscCall(PetscViewerGetFormat(viewer, &format)); 2588 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2589 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2590 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2591 #else 2592 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2593 #endif 2594 } 2595 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2596 PetscFunctionReturn(PETSC_SUCCESS); 2597 } 2598 2599 /*@ 2600 DMPlexSectionLoad - Loads section into a `DMPLEX` 2601 2602 Collective 2603 2604 Input Parameters: 2605 + dm - The `DM` that represents the topology 2606 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2607 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2608 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2609 2610 Output Parameters: 2611 + 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) 2612 - 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) 2613 2614 Level: advanced 2615 2616 Notes: 2617 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. 2618 2619 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. 2620 2621 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. 2622 2623 Example using 2 processes: 2624 .vb 2625 NX (number of points on dm): 4 2626 sectionA : the on-disk section 2627 vecA : a vector associated with sectionA 2628 sectionB : sectiondm's local section constructed in this function 2629 vecB (local) : a vector associated with sectiondm's local section 2630 vecB (global) : a vector associated with sectiondm's global section 2631 2632 rank 0 rank 1 2633 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2634 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2635 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2636 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2637 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2638 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2639 sectionB->atlasDof : 1 0 1 | 1 3 2640 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2641 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2642 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2643 .ve 2644 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2645 2646 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2647 @*/ 2648 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, PeOp DM sectiondm, PetscSF globalToLocalPointSF, PeOp PetscSF *globalDofSF, PeOp PetscSF *localDofSF) 2649 { 2650 PetscBool ishdf5; 2651 2652 PetscFunctionBegin; 2653 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2654 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2655 if (!sectiondm) sectiondm = dm; 2656 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2657 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2658 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2659 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2660 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2661 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2662 if (ishdf5) { 2663 #if defined(PETSC_HAVE_HDF5) 2664 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2665 #else 2666 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2667 #endif 2668 } 2669 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2670 PetscFunctionReturn(PETSC_SUCCESS); 2671 } 2672 2673 /*@ 2674 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2675 2676 Collective 2677 2678 Input Parameters: 2679 + dm - The `DM` that represents the topology 2680 . viewer - The `PetscViewer` that represents the on-disk vector data 2681 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2682 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2683 - vec - The global vector to set values of 2684 2685 Level: advanced 2686 2687 Notes: 2688 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. 2689 2690 Calling sequence: 2691 .vb 2692 DMCreate(PETSC_COMM_WORLD, &dm); 2693 DMSetType(dm, DMPLEX); 2694 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2695 DMPlexTopologyLoad(dm, viewer, &sfX); 2696 DMClone(dm, §iondm); 2697 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2698 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2699 DMGetGlobalVector(sectiondm, &vec); 2700 PetscObjectSetName((PetscObject)vec, "vec_name"); 2701 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2702 DMRestoreGlobalVector(sectiondm, &vec); 2703 PetscSFDestroy(&gsf); 2704 PetscSFDestroy(&sfX); 2705 DMDestroy(§iondm); 2706 DMDestroy(&dm); 2707 .ve 2708 2709 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2710 `PetscSF`, `PetscViewer` 2711 @*/ 2712 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2713 { 2714 PetscBool ishdf5; 2715 2716 PetscFunctionBegin; 2717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2718 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2719 if (!sectiondm) sectiondm = dm; 2720 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2721 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2722 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2723 /* Check consistency */ 2724 { 2725 PetscSection section; 2726 PetscBool includesConstraints; 2727 PetscInt m, m1; 2728 2729 PetscCall(VecGetLocalSize(vec, &m1)); 2730 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2731 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2732 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2733 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2734 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2735 } 2736 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2737 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2738 if (ishdf5) { 2739 #if defined(PETSC_HAVE_HDF5) 2740 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2741 #else 2742 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2743 #endif 2744 } 2745 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2746 PetscFunctionReturn(PETSC_SUCCESS); 2747 } 2748 2749 /*@ 2750 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2751 2752 Collective 2753 2754 Input Parameters: 2755 + dm - The `DM` that represents the topology 2756 . viewer - The `PetscViewer` that represents the on-disk vector data 2757 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2758 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2759 - vec - The local vector to set values of 2760 2761 Level: advanced 2762 2763 Notes: 2764 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. 2765 2766 Calling sequence: 2767 .vb 2768 DMCreate(PETSC_COMM_WORLD, &dm); 2769 DMSetType(dm, DMPLEX); 2770 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2771 DMPlexTopologyLoad(dm, viewer, &sfX); 2772 DMClone(dm, §iondm); 2773 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2774 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2775 DMGetLocalVector(sectiondm, &vec); 2776 PetscObjectSetName((PetscObject)vec, "vec_name"); 2777 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2778 DMRestoreLocalVector(sectiondm, &vec); 2779 PetscSFDestroy(&lsf); 2780 PetscSFDestroy(&sfX); 2781 DMDestroy(§iondm); 2782 DMDestroy(&dm); 2783 .ve 2784 2785 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2786 `PetscSF`, `PetscViewer` 2787 @*/ 2788 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2789 { 2790 PetscBool ishdf5; 2791 2792 PetscFunctionBegin; 2793 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2794 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2795 if (!sectiondm) sectiondm = dm; 2796 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2797 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2798 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2799 /* Check consistency */ 2800 { 2801 PetscSection section; 2802 PetscBool includesConstraints; 2803 PetscInt m, m1; 2804 2805 PetscCall(VecGetLocalSize(vec, &m1)); 2806 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2807 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2808 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2809 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2810 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2811 } 2812 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2813 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2814 if (ishdf5) { 2815 #if defined(PETSC_HAVE_HDF5) 2816 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2817 #else 2818 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2819 #endif 2820 } 2821 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2822 PetscFunctionReturn(PETSC_SUCCESS); 2823 } 2824 2825 PetscErrorCode DMDestroy_Plex(DM dm) 2826 { 2827 DM_Plex *mesh = (DM_Plex *)dm->data; 2828 2829 PetscFunctionBegin; 2830 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2831 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2832 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2833 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBounds_C", NULL)); 2834 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2835 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2836 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2837 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2838 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2839 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2840 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2841 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2842 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2843 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2844 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2845 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2846 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2847 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2848 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2849 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2850 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2851 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2852 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2853 PetscCall(PetscFree(mesh->cones)); 2854 PetscCall(PetscFree(mesh->coneOrientations)); 2855 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2856 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2857 PetscCall(PetscFree(mesh->supports)); 2858 PetscCall(PetscFree(mesh->cellTypes)); 2859 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2860 PetscCall(PetscFree(mesh->tetgenOpts)); 2861 PetscCall(PetscFree(mesh->triangleOpts)); 2862 PetscCall(PetscFree(mesh->transformType)); 2863 PetscCall(PetscFree(mesh->distributionName)); 2864 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2865 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2866 PetscCall(ISDestroy(&mesh->subpointIS)); 2867 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2868 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2869 if (mesh->periodic.face_sfs) { 2870 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2871 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2872 } 2873 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2874 if (mesh->periodic.periodic_points) { 2875 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2876 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2877 } 2878 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2879 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2880 PetscCall(ISDestroy(&mesh->anchorIS)); 2881 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2882 PetscCall(PetscFree(mesh->parents)); 2883 PetscCall(PetscFree(mesh->childIDs)); 2884 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2885 PetscCall(PetscFree(mesh->children)); 2886 PetscCall(DMDestroy(&mesh->referenceTree)); 2887 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2888 PetscCall(PetscFree(mesh->neighbors)); 2889 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2890 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2891 PetscCall(DMPlexTransformDestroy(&mesh->transform)); 2892 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2893 PetscCall(PetscFree(mesh)); 2894 PetscFunctionReturn(PETSC_SUCCESS); 2895 } 2896 2897 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2898 { 2899 PetscSection sectionGlobal, sectionLocal; 2900 PetscInt bs = -1, mbs; 2901 PetscInt localSize, localStart = 0; 2902 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2903 MatType mtype; 2904 ISLocalToGlobalMapping ltog; 2905 2906 PetscFunctionBegin; 2907 PetscCall(MatInitializePackage()); 2908 mtype = dm->mattype; 2909 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2910 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2911 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2912 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2913 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2914 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2915 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2916 PetscCall(MatSetType(*J, mtype)); 2917 PetscCall(MatSetFromOptions(*J)); 2918 PetscCall(MatGetBlockSize(*J, &mbs)); 2919 if (mbs > 1) bs = mbs; 2920 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2921 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2922 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2923 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2924 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2925 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2926 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2927 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2928 if (!isShell) { 2929 // There are three states with pblocks, since block starts can have no dofs: 2930 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2931 // TRUE) Block Start: The first entry in a block has been added 2932 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2933 PetscBT blst; 2934 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2935 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2936 const PetscInt *perm = NULL; 2937 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2938 PetscInt pStart, pEnd, dof, cdof, num_fields; 2939 2940 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2941 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2942 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2943 2944 PetscCall(PetscCalloc1(localSize, &pblocks)); 2945 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2946 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2947 // We need to process in the permuted order to get block sizes right 2948 for (PetscInt point = pStart; point < pEnd; ++point) { 2949 const PetscInt p = perm ? perm[point] : point; 2950 2951 switch (dm->blocking_type) { 2952 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2953 PetscInt bdof, offset; 2954 2955 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2956 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2957 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2958 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2959 if (dof > 0) { 2960 // State change 2961 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2962 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2963 2964 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2965 // Signal block concatenation 2966 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2967 } 2968 dof = dof < 0 ? -(dof + 1) : dof; 2969 bdof = cdof && (dof - cdof) ? 1 : dof; 2970 if (dof) { 2971 if (bs < 0) { 2972 bs = bdof; 2973 } else if (bs != bdof) { 2974 bs = 1; 2975 } 2976 } 2977 } break; 2978 case DM_BLOCKING_FIELD_NODE: { 2979 for (PetscInt field = 0; field < num_fields; field++) { 2980 PetscInt num_comp, bdof, offset; 2981 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2982 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2983 if (dof < 0) continue; 2984 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2985 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2986 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); 2987 PetscInt num_nodes = dof / num_comp; 2988 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2989 // Handle possibly constant block size (unlikely) 2990 bdof = cdof && (dof - cdof) ? 1 : dof; 2991 if (dof) { 2992 if (bs < 0) { 2993 bs = bdof; 2994 } else if (bs != bdof) { 2995 bs = 1; 2996 } 2997 } 2998 } 2999 } break; 3000 } 3001 } 3002 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 3003 /* Must have same blocksize on all procs (some might have no points) */ 3004 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 3005 bsLocal[1] = bs; 3006 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 3007 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 3008 else bs = bsMinMax[0]; 3009 bs = PetscMax(1, bs); 3010 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 3011 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 3012 PetscCall(MatSetBlockSize(*J, bs)); 3013 PetscCall(MatSetUp(*J)); 3014 } else { 3015 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 3016 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 3017 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 3018 } 3019 if (pblocks) { // Consolidate blocks 3020 PetscInt nblocks = 0; 3021 pblocks[0] = PetscAbs(pblocks[0]); 3022 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 3023 if (pblocks[i] == 0) continue; 3024 // Negative block size indicates the blocks should be concatenated 3025 if (pblocks[i] < 0) { 3026 pblocks[i] = -pblocks[i]; 3027 pblocks[nblocks - 1] += pblocks[i]; 3028 } else { 3029 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 3030 } 3031 for (PetscInt j = 1; j < pblocks[i]; j++) 3032 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); 3033 } 3034 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 3035 } 3036 PetscCall(PetscFree(pblocks)); 3037 } 3038 PetscCall(MatSetDM(*J, dm)); 3039 PetscFunctionReturn(PETSC_SUCCESS); 3040 } 3041 3042 /*@ 3043 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 3044 3045 Not Collective 3046 3047 Input Parameter: 3048 . dm - The `DMPLEX` 3049 3050 Output Parameter: 3051 . subsection - The subdomain section 3052 3053 Level: developer 3054 3055 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 3056 @*/ 3057 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 3058 { 3059 DM_Plex *mesh = (DM_Plex *)dm->data; 3060 3061 PetscFunctionBegin; 3062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3063 if (!mesh->subdomainSection) { 3064 PetscSection section; 3065 PetscSF sf; 3066 3067 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 3068 PetscCall(DMGetLocalSection(dm, §ion)); 3069 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 3070 PetscCall(PetscSFDestroy(&sf)); 3071 } 3072 *subsection = mesh->subdomainSection; 3073 PetscFunctionReturn(PETSC_SUCCESS); 3074 } 3075 3076 /*@ 3077 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 3078 3079 Not Collective 3080 3081 Input Parameter: 3082 . dm - The `DMPLEX` 3083 3084 Output Parameters: 3085 + pStart - The first mesh point 3086 - pEnd - The upper bound for mesh points 3087 3088 Level: beginner 3089 3090 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3091 @*/ 3092 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3093 { 3094 DM_Plex *mesh = (DM_Plex *)dm->data; 3095 3096 PetscFunctionBegin; 3097 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3098 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3099 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3100 PetscFunctionReturn(PETSC_SUCCESS); 3101 } 3102 3103 /*@ 3104 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3105 3106 Not Collective 3107 3108 Input Parameters: 3109 + dm - The `DMPLEX` 3110 . pStart - The first mesh point 3111 - pEnd - The upper bound for mesh points 3112 3113 Level: beginner 3114 3115 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3116 @*/ 3117 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3118 { 3119 DM_Plex *mesh = (DM_Plex *)dm->data; 3120 3121 PetscFunctionBegin; 3122 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3123 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3124 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3125 PetscCall(PetscFree(mesh->cellTypes)); 3126 PetscFunctionReturn(PETSC_SUCCESS); 3127 } 3128 3129 /*@ 3130 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3131 3132 Not Collective 3133 3134 Input Parameters: 3135 + dm - The `DMPLEX` 3136 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3137 3138 Output Parameter: 3139 . size - The cone size for point `p` 3140 3141 Level: beginner 3142 3143 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3144 @*/ 3145 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3146 { 3147 DM_Plex *mesh = (DM_Plex *)dm->data; 3148 3149 PetscFunctionBegin; 3150 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3151 PetscAssertPointer(size, 3); 3152 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3153 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3154 PetscFunctionReturn(PETSC_SUCCESS); 3155 } 3156 3157 /*@ 3158 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3159 3160 Not Collective 3161 3162 Input Parameters: 3163 + dm - The `DMPLEX` 3164 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3165 - size - The cone size for point `p` 3166 3167 Level: beginner 3168 3169 Note: 3170 This should be called after `DMPlexSetChart()`. 3171 3172 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3173 @*/ 3174 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3175 { 3176 DM_Plex *mesh = (DM_Plex *)dm->data; 3177 3178 PetscFunctionBegin; 3179 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3180 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3181 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3182 PetscFunctionReturn(PETSC_SUCCESS); 3183 } 3184 3185 /*@C 3186 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3187 3188 Not Collective 3189 3190 Input Parameters: 3191 + dm - The `DMPLEX` 3192 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3193 3194 Output Parameter: 3195 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3196 3197 Level: beginner 3198 3199 Fortran Notes: 3200 `cone` must be declared with 3201 .vb 3202 PetscInt, pointer :: cone(:) 3203 .ve 3204 3205 You must call `DMPlexRestoreCone()` after you finish using the array. 3206 `DMPlexRestoreCone()` is not needed/available in C. 3207 3208 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3209 @*/ 3210 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3211 { 3212 DM_Plex *mesh = (DM_Plex *)dm->data; 3213 PetscInt off; 3214 3215 PetscFunctionBegin; 3216 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3217 PetscAssertPointer(cone, 3); 3218 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3219 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3220 PetscFunctionReturn(PETSC_SUCCESS); 3221 } 3222 3223 /*@ 3224 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3225 3226 Not Collective 3227 3228 Input Parameters: 3229 + dm - The `DMPLEX` 3230 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3231 3232 Output Parameters: 3233 + pConesSection - `PetscSection` describing the layout of `pCones` 3234 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3235 3236 Level: intermediate 3237 3238 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3239 @*/ 3240 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PeOp PetscSection *pConesSection, PeOp IS *pCones) 3241 { 3242 PetscSection cs, newcs; 3243 PetscInt *cones; 3244 PetscInt *newarr = NULL; 3245 PetscInt n; 3246 3247 PetscFunctionBegin; 3248 PetscCall(DMPlexGetCones(dm, &cones)); 3249 PetscCall(DMPlexGetConeSection(dm, &cs)); 3250 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3251 if (pConesSection) *pConesSection = newcs; 3252 if (pCones) { 3253 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3254 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3255 } 3256 PetscFunctionReturn(PETSC_SUCCESS); 3257 } 3258 3259 /*@ 3260 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3261 3262 Not Collective 3263 3264 Input Parameters: 3265 + dm - The `DMPLEX` 3266 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3267 3268 Output Parameter: 3269 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3270 3271 Level: advanced 3272 3273 Notes: 3274 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3275 3276 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3277 3278 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3279 `DMPlexGetDepth()`, `IS` 3280 @*/ 3281 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3282 { 3283 IS *expandedPointsAll; 3284 PetscInt depth; 3285 3286 PetscFunctionBegin; 3287 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3288 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3289 PetscAssertPointer(expandedPoints, 3); 3290 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3291 *expandedPoints = expandedPointsAll[0]; 3292 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3293 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3294 PetscFunctionReturn(PETSC_SUCCESS); 3295 } 3296 3297 /*@ 3298 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3299 (DAG points of depth 0, i.e., without cones). 3300 3301 Not Collective 3302 3303 Input Parameters: 3304 + dm - The `DMPLEX` 3305 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3306 3307 Output Parameters: 3308 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3309 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3310 - sections - (optional) An array of sections which describe mappings from points to their cone points 3311 3312 Level: advanced 3313 3314 Notes: 3315 Like `DMPlexGetConeTuple()` but recursive. 3316 3317 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. 3318 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3319 3320 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\: 3321 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3322 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3323 3324 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3325 `DMPlexGetDepth()`, `PetscSection`, `IS` 3326 @*/ 3327 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3328 { 3329 const PetscInt *arr0 = NULL, *cone = NULL; 3330 PetscInt *arr = NULL, *newarr = NULL; 3331 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3332 IS *expandedPoints_; 3333 PetscSection *sections_; 3334 3335 PetscFunctionBegin; 3336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3337 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3338 if (depth) PetscAssertPointer(depth, 3); 3339 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3340 if (sections) PetscAssertPointer(sections, 5); 3341 PetscCall(ISGetLocalSize(points, &n)); 3342 PetscCall(ISGetIndices(points, &arr0)); 3343 PetscCall(DMPlexGetDepth(dm, &depth_)); 3344 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3345 PetscCall(PetscCalloc1(depth_, §ions_)); 3346 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3347 for (d = depth_ - 1; d >= 0; d--) { 3348 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3349 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3350 for (i = 0; i < n; i++) { 3351 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3352 if (arr[i] >= start && arr[i] < end) { 3353 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3354 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3355 } else { 3356 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3357 } 3358 } 3359 PetscCall(PetscSectionSetUp(sections_[d])); 3360 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3361 PetscCall(PetscMalloc1(newn, &newarr)); 3362 for (i = 0; i < n; i++) { 3363 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3364 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3365 if (cn > 1) { 3366 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3367 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3368 } else { 3369 newarr[co] = arr[i]; 3370 } 3371 } 3372 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3373 arr = newarr; 3374 n = newn; 3375 } 3376 PetscCall(ISRestoreIndices(points, &arr0)); 3377 *depth = depth_; 3378 if (expandedPoints) *expandedPoints = expandedPoints_; 3379 else { 3380 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3381 PetscCall(PetscFree(expandedPoints_)); 3382 } 3383 if (sections) *sections = sections_; 3384 else { 3385 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3386 PetscCall(PetscFree(sections_)); 3387 } 3388 PetscFunctionReturn(PETSC_SUCCESS); 3389 } 3390 3391 /*@ 3392 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3393 3394 Not Collective 3395 3396 Input Parameters: 3397 + dm - The `DMPLEX` 3398 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3399 3400 Output Parameters: 3401 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3402 . expandedPoints - (optional) An array of recursively expanded cones 3403 - sections - (optional) An array of sections which describe mappings from points to their cone points 3404 3405 Level: advanced 3406 3407 Note: 3408 See `DMPlexGetConeRecursive()` 3409 3410 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3411 `DMPlexGetDepth()`, `IS`, `PetscSection` 3412 @*/ 3413 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3414 { 3415 PetscInt d, depth_; 3416 3417 PetscFunctionBegin; 3418 PetscCall(DMPlexGetDepth(dm, &depth_)); 3419 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3420 if (depth) *depth = 0; 3421 if (expandedPoints) { 3422 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3423 PetscCall(PetscFree(*expandedPoints)); 3424 } 3425 if (sections) { 3426 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3427 PetscCall(PetscFree(*sections)); 3428 } 3429 PetscFunctionReturn(PETSC_SUCCESS); 3430 } 3431 3432 /*@ 3433 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 3434 3435 Not Collective 3436 3437 Input Parameters: 3438 + dm - The `DMPLEX` 3439 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3440 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3441 3442 Level: beginner 3443 3444 Note: 3445 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3446 3447 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3448 @*/ 3449 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3450 { 3451 DM_Plex *mesh = (DM_Plex *)dm->data; 3452 PetscInt dof, off, c; 3453 3454 PetscFunctionBegin; 3455 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3456 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3457 if (dof) PetscAssertPointer(cone, 3); 3458 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3459 if (PetscDefined(USE_DEBUG)) { 3460 PetscInt pStart, pEnd; 3461 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3462 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); 3463 for (c = 0; c < dof; ++c) { 3464 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); 3465 mesh->cones[off + c] = cone[c]; 3466 } 3467 } else { 3468 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3469 } 3470 PetscFunctionReturn(PETSC_SUCCESS); 3471 } 3472 3473 /*@C 3474 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3475 3476 Not Collective 3477 3478 Input Parameters: 3479 + dm - The `DMPLEX` 3480 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3481 3482 Output Parameter: 3483 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3484 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3485 3486 Level: beginner 3487 3488 Note: 3489 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3490 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3491 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3492 with the identity. 3493 3494 Fortran Notes: 3495 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3496 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3497 3498 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3499 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3500 @*/ 3501 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3502 { 3503 DM_Plex *mesh = (DM_Plex *)dm->data; 3504 PetscInt off; 3505 3506 PetscFunctionBegin; 3507 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3508 if (PetscDefined(USE_DEBUG)) { 3509 PetscInt dof; 3510 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3511 if (dof) PetscAssertPointer(coneOrientation, 3); 3512 } 3513 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3514 3515 *coneOrientation = &mesh->coneOrientations[off]; 3516 PetscFunctionReturn(PETSC_SUCCESS); 3517 } 3518 3519 /*@ 3520 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3521 3522 Not Collective 3523 3524 Input Parameters: 3525 + dm - The `DMPLEX` 3526 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3527 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3528 3529 Level: beginner 3530 3531 Notes: 3532 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3533 3534 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3535 3536 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3537 @*/ 3538 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3539 { 3540 DM_Plex *mesh = (DM_Plex *)dm->data; 3541 PetscInt pStart, pEnd; 3542 PetscInt dof, off, c; 3543 3544 PetscFunctionBegin; 3545 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3546 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3547 if (dof) PetscAssertPointer(coneOrientation, 3); 3548 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3549 if (PetscDefined(USE_DEBUG)) { 3550 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3551 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); 3552 for (c = 0; c < dof; ++c) { 3553 PetscInt cdof, o = coneOrientation[c]; 3554 3555 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3556 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); 3557 mesh->coneOrientations[off + c] = o; 3558 } 3559 } else { 3560 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3561 } 3562 PetscFunctionReturn(PETSC_SUCCESS); 3563 } 3564 3565 /*@ 3566 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3567 3568 Not Collective 3569 3570 Input Parameters: 3571 + dm - The `DMPLEX` 3572 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3573 . conePos - The local index in the cone where the point should be put 3574 - conePoint - The mesh point to insert 3575 3576 Level: beginner 3577 3578 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3579 @*/ 3580 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3581 { 3582 DM_Plex *mesh = (DM_Plex *)dm->data; 3583 PetscInt pStart, pEnd; 3584 PetscInt dof, off; 3585 3586 PetscFunctionBegin; 3587 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3588 if (PetscDefined(USE_DEBUG)) { 3589 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3590 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); 3591 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); 3592 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3593 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); 3594 } 3595 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3596 mesh->cones[off + conePos] = conePoint; 3597 PetscFunctionReturn(PETSC_SUCCESS); 3598 } 3599 3600 /*@ 3601 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3602 3603 Not Collective 3604 3605 Input Parameters: 3606 + dm - The `DMPLEX` 3607 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3608 . conePos - The local index in the cone where the point should be put 3609 - coneOrientation - The point orientation to insert 3610 3611 Level: beginner 3612 3613 Note: 3614 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3615 3616 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3617 @*/ 3618 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3619 { 3620 DM_Plex *mesh = (DM_Plex *)dm->data; 3621 PetscInt pStart, pEnd; 3622 PetscInt dof, off; 3623 3624 PetscFunctionBegin; 3625 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3626 if (PetscDefined(USE_DEBUG)) { 3627 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3628 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); 3629 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3630 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); 3631 } 3632 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3633 mesh->coneOrientations[off + conePos] = coneOrientation; 3634 PetscFunctionReturn(PETSC_SUCCESS); 3635 } 3636 3637 /*@C 3638 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3639 3640 Not collective 3641 3642 Input Parameters: 3643 + dm - The DMPlex 3644 - p - The point, which must lie in the chart set with DMPlexSetChart() 3645 3646 Output Parameters: 3647 + cone - An array of points which are on the in-edges for point `p` 3648 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3649 integer giving the prescription for cone traversal. 3650 3651 Level: beginner 3652 3653 Notes: 3654 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3655 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3656 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3657 with the identity. 3658 3659 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3660 3661 Fortran Notes: 3662 `cone` and `ornt` must be declared with 3663 .vb 3664 PetscInt, pointer :: cone(:) 3665 PetscInt, pointer :: ornt(:) 3666 .ve 3667 3668 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3669 @*/ 3670 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, PeOp const PetscInt *cone[], PeOp const PetscInt *ornt[]) 3671 { 3672 DM_Plex *mesh = (DM_Plex *)dm->data; 3673 3674 PetscFunctionBegin; 3675 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3676 if (mesh->tr) { 3677 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3678 } else { 3679 PetscInt off; 3680 if (PetscDefined(USE_DEBUG)) { 3681 PetscInt dof; 3682 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3683 if (dof) { 3684 if (cone) PetscAssertPointer(cone, 3); 3685 if (ornt) PetscAssertPointer(ornt, 4); 3686 } 3687 } 3688 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3689 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3690 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3691 } 3692 PetscFunctionReturn(PETSC_SUCCESS); 3693 } 3694 3695 /*@C 3696 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3697 3698 Not Collective 3699 3700 Input Parameters: 3701 + dm - The DMPlex 3702 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3703 . cone - An array of points which are on the in-edges for point p 3704 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3705 integer giving the prescription for cone traversal. 3706 3707 Level: beginner 3708 3709 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3710 @*/ 3711 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3712 { 3713 DM_Plex *mesh = (DM_Plex *)dm->data; 3714 3715 PetscFunctionBegin; 3716 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3717 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3718 PetscFunctionReturn(PETSC_SUCCESS); 3719 } 3720 3721 /*@ 3722 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3723 3724 Not Collective 3725 3726 Input Parameters: 3727 + dm - The `DMPLEX` 3728 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3729 3730 Output Parameter: 3731 . size - The support size for point `p` 3732 3733 Level: beginner 3734 3735 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3736 @*/ 3737 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3738 { 3739 DM_Plex *mesh = (DM_Plex *)dm->data; 3740 3741 PetscFunctionBegin; 3742 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3743 PetscAssertPointer(size, 3); 3744 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3745 PetscFunctionReturn(PETSC_SUCCESS); 3746 } 3747 3748 /*@ 3749 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3750 3751 Not Collective 3752 3753 Input Parameters: 3754 + dm - The `DMPLEX` 3755 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3756 - size - The support size for point `p` 3757 3758 Level: beginner 3759 3760 Note: 3761 This should be called after `DMPlexSetChart()`. 3762 3763 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3764 @*/ 3765 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3766 { 3767 DM_Plex *mesh = (DM_Plex *)dm->data; 3768 3769 PetscFunctionBegin; 3770 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3771 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3772 PetscFunctionReturn(PETSC_SUCCESS); 3773 } 3774 3775 /*@C 3776 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3777 3778 Not Collective 3779 3780 Input Parameters: 3781 + dm - The `DMPLEX` 3782 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3783 3784 Output Parameter: 3785 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3786 3787 Level: beginner 3788 3789 Fortran Notes: 3790 `support` must be declared with 3791 .vb 3792 PetscInt, pointer :: support(:) 3793 .ve 3794 3795 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3796 `DMPlexRestoreSupport()` is not needed/available in C. 3797 3798 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3799 @*/ 3800 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3801 { 3802 DM_Plex *mesh = (DM_Plex *)dm->data; 3803 PetscInt off; 3804 3805 PetscFunctionBegin; 3806 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3807 PetscAssertPointer(support, 3); 3808 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3809 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3810 PetscFunctionReturn(PETSC_SUCCESS); 3811 } 3812 3813 /*@ 3814 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3815 3816 Not Collective 3817 3818 Input Parameters: 3819 + dm - The `DMPLEX` 3820 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3821 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3822 3823 Level: beginner 3824 3825 Note: 3826 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3827 3828 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3829 @*/ 3830 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3831 { 3832 DM_Plex *mesh = (DM_Plex *)dm->data; 3833 PetscInt pStart, pEnd; 3834 PetscInt dof, off, c; 3835 3836 PetscFunctionBegin; 3837 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3838 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3839 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3840 if (dof) PetscAssertPointer(support, 3); 3841 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3842 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); 3843 for (c = 0; c < dof; ++c) { 3844 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); 3845 mesh->supports[off + c] = support[c]; 3846 } 3847 PetscFunctionReturn(PETSC_SUCCESS); 3848 } 3849 3850 /*@ 3851 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3852 3853 Not Collective 3854 3855 Input Parameters: 3856 + dm - The `DMPLEX` 3857 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3858 . supportPos - The local index in the cone where the point should be put 3859 - supportPoint - The mesh point to insert 3860 3861 Level: beginner 3862 3863 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3864 @*/ 3865 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3866 { 3867 DM_Plex *mesh = (DM_Plex *)dm->data; 3868 PetscInt pStart, pEnd; 3869 PetscInt dof, off; 3870 3871 PetscFunctionBegin; 3872 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3873 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3874 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3875 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3876 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); 3877 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); 3878 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); 3879 mesh->supports[off + supportPos] = supportPoint; 3880 PetscFunctionReturn(PETSC_SUCCESS); 3881 } 3882 3883 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3884 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3885 { 3886 switch (ct) { 3887 case DM_POLYTOPE_SEGMENT: 3888 if (o == -1) return -2; 3889 break; 3890 case DM_POLYTOPE_TRIANGLE: 3891 if (o == -3) return -1; 3892 if (o == -2) return -3; 3893 if (o == -1) return -2; 3894 break; 3895 case DM_POLYTOPE_QUADRILATERAL: 3896 if (o == -4) return -2; 3897 if (o == -3) return -1; 3898 if (o == -2) return -4; 3899 if (o == -1) return -3; 3900 break; 3901 default: 3902 return o; 3903 } 3904 return o; 3905 } 3906 3907 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3908 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3909 { 3910 switch (ct) { 3911 case DM_POLYTOPE_SEGMENT: 3912 if ((o == -2) || (o == 1)) return -1; 3913 if (o == -1) return 0; 3914 break; 3915 case DM_POLYTOPE_TRIANGLE: 3916 if (o == -3) return -2; 3917 if (o == -2) return -1; 3918 if (o == -1) return -3; 3919 break; 3920 case DM_POLYTOPE_QUADRILATERAL: 3921 if (o == -4) return -2; 3922 if (o == -3) return -1; 3923 if (o == -2) return -4; 3924 if (o == -1) return -3; 3925 break; 3926 default: 3927 return o; 3928 } 3929 return o; 3930 } 3931 3932 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3933 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3934 { 3935 PetscInt pStart, pEnd, p; 3936 3937 PetscFunctionBegin; 3938 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3939 for (p = pStart; p < pEnd; ++p) { 3940 const PetscInt *cone, *ornt; 3941 PetscInt coneSize, c; 3942 3943 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3944 PetscCall(DMPlexGetCone(dm, p, &cone)); 3945 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3946 for (c = 0; c < coneSize; ++c) { 3947 DMPolytopeType ct; 3948 const PetscInt o = ornt[c]; 3949 3950 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3951 switch (ct) { 3952 case DM_POLYTOPE_SEGMENT: 3953 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3954 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3955 break; 3956 case DM_POLYTOPE_TRIANGLE: 3957 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3958 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3959 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3960 break; 3961 case DM_POLYTOPE_QUADRILATERAL: 3962 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3963 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3964 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3965 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3966 break; 3967 default: 3968 break; 3969 } 3970 } 3971 } 3972 PetscFunctionReturn(PETSC_SUCCESS); 3973 } 3974 3975 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3976 { 3977 DM_Plex *mesh = (DM_Plex *)dm->data; 3978 3979 PetscFunctionBeginHot; 3980 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3981 if (useCone) { 3982 PetscCall(DMPlexGetConeSize(dm, p, size)); 3983 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3984 } else { 3985 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3986 PetscCall(DMPlexGetSupport(dm, p, arr)); 3987 } 3988 } else { 3989 if (useCone) { 3990 const PetscSection s = mesh->coneSection; 3991 const PetscInt ps = p - s->pStart; 3992 const PetscInt off = s->atlasOff[ps]; 3993 3994 *size = s->atlasDof[ps]; 3995 *arr = mesh->cones + off; 3996 *ornt = mesh->coneOrientations + off; 3997 } else { 3998 const PetscSection s = mesh->supportSection; 3999 const PetscInt ps = p - s->pStart; 4000 const PetscInt off = s->atlasOff[ps]; 4001 4002 *size = s->atlasDof[ps]; 4003 *arr = mesh->supports + off; 4004 } 4005 } 4006 PetscFunctionReturn(PETSC_SUCCESS); 4007 } 4008 4009 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 4010 { 4011 DM_Plex *mesh = (DM_Plex *)dm->data; 4012 4013 PetscFunctionBeginHot; 4014 if (PetscDefined(USE_DEBUG) || mesh->tr) { 4015 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 4016 } 4017 PetscFunctionReturn(PETSC_SUCCESS); 4018 } 4019 4020 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4021 { 4022 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4023 PetscInt *closure; 4024 const PetscInt *tmp = NULL, *tmpO = NULL; 4025 PetscInt off = 0, tmpSize, t; 4026 4027 PetscFunctionBeginHot; 4028 if (ornt) { 4029 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4030 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; 4031 } 4032 if (*points) { 4033 closure = *points; 4034 } else { 4035 PetscInt maxConeSize, maxSupportSize; 4036 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4037 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 4038 } 4039 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4040 if (ct == DM_POLYTOPE_UNKNOWN) { 4041 closure[off++] = p; 4042 closure[off++] = 0; 4043 for (t = 0; t < tmpSize; ++t) { 4044 closure[off++] = tmp[t]; 4045 closure[off++] = tmpO ? tmpO[t] : 0; 4046 } 4047 } else { 4048 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 4049 4050 /* We assume that cells with a valid type have faces with a valid type */ 4051 closure[off++] = p; 4052 closure[off++] = ornt; 4053 for (t = 0; t < tmpSize; ++t) { 4054 DMPolytopeType ft; 4055 4056 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 4057 closure[off++] = tmp[arr[t]]; 4058 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 4059 } 4060 } 4061 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4062 if (numPoints) *numPoints = tmpSize + 1; 4063 if (points) *points = closure; 4064 PetscFunctionReturn(PETSC_SUCCESS); 4065 } 4066 4067 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 4068 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 4069 { 4070 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 4071 const PetscInt *cone, *ornt; 4072 PetscInt *pts, *closure = NULL; 4073 DMPolytopeType ft; 4074 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 4075 PetscInt dim, coneSize, c, d, clSize, cl; 4076 4077 PetscFunctionBeginHot; 4078 PetscCall(DMGetDimension(dm, &dim)); 4079 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4080 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4081 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4082 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4083 maxSize = PetscMax(coneSeries, supportSeries); 4084 if (*points) { 4085 pts = *points; 4086 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4087 c = 0; 4088 pts[c++] = point; 4089 pts[c++] = o; 4090 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4091 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4092 for (cl = 0; cl < clSize * 2; cl += 2) { 4093 pts[c++] = closure[cl]; 4094 pts[c++] = closure[cl + 1]; 4095 } 4096 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4097 for (cl = 0; cl < clSize * 2; cl += 2) { 4098 pts[c++] = closure[cl]; 4099 pts[c++] = closure[cl + 1]; 4100 } 4101 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4102 for (d = 2; d < coneSize; ++d) { 4103 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4104 pts[c++] = cone[arr[d * 2 + 0]]; 4105 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4106 } 4107 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4108 if (dim >= 3) { 4109 for (d = 2; d < coneSize; ++d) { 4110 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4111 const PetscInt *fcone, *fornt; 4112 PetscInt fconeSize, fc, i; 4113 4114 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4115 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4116 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4117 for (fc = 0; fc < fconeSize; ++fc) { 4118 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4119 const PetscInt co = farr[fc * 2 + 1]; 4120 4121 for (i = 0; i < c; i += 2) 4122 if (pts[i] == cp) break; 4123 if (i == c) { 4124 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4125 pts[c++] = cp; 4126 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4127 } 4128 } 4129 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4130 } 4131 } 4132 *numPoints = c / 2; 4133 *points = pts; 4134 PetscFunctionReturn(PETSC_SUCCESS); 4135 } 4136 4137 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4138 { 4139 DMPolytopeType ct; 4140 PetscInt *closure, *fifo; 4141 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4142 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4143 PetscInt depth, maxSize; 4144 4145 PetscFunctionBeginHot; 4146 PetscCall(DMPlexGetDepth(dm, &depth)); 4147 if (depth == 1) { 4148 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4149 PetscFunctionReturn(PETSC_SUCCESS); 4150 } 4151 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4152 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; 4153 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4154 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4155 PetscFunctionReturn(PETSC_SUCCESS); 4156 } 4157 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4158 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4159 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4160 maxSize = PetscMax(coneSeries, supportSeries); 4161 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4162 if (*points) { 4163 closure = *points; 4164 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4165 closure[closureSize++] = p; 4166 closure[closureSize++] = ornt; 4167 fifo[fifoSize++] = p; 4168 fifo[fifoSize++] = ornt; 4169 fifo[fifoSize++] = ct; 4170 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4171 while (fifoSize - fifoStart) { 4172 const PetscInt q = fifo[fifoStart++]; 4173 const PetscInt o = fifo[fifoStart++]; 4174 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4175 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4176 const PetscInt *tmp, *tmpO = NULL; 4177 PetscInt tmpSize, t; 4178 4179 if (PetscDefined(USE_DEBUG)) { 4180 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4181 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); 4182 } 4183 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4184 for (t = 0; t < tmpSize; ++t) { 4185 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4186 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4187 const PetscInt cp = tmp[ip]; 4188 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4189 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4190 PetscInt c; 4191 4192 /* Check for duplicate */ 4193 for (c = 0; c < closureSize; c += 2) { 4194 if (closure[c] == cp) break; 4195 } 4196 if (c == closureSize) { 4197 closure[closureSize++] = cp; 4198 closure[closureSize++] = co; 4199 fifo[fifoSize++] = cp; 4200 fifo[fifoSize++] = co; 4201 fifo[fifoSize++] = ct; 4202 } 4203 } 4204 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4205 } 4206 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4207 if (numPoints) *numPoints = closureSize / 2; 4208 if (points) *points = closure; 4209 PetscFunctionReturn(PETSC_SUCCESS); 4210 } 4211 4212 /*@C 4213 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4214 4215 Not Collective 4216 4217 Input Parameters: 4218 + dm - The `DMPLEX` 4219 . p - The mesh point 4220 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4221 4222 Input/Output Parameter: 4223 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4224 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4225 otherwise the provided array is used to hold the values 4226 4227 Output Parameter: 4228 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4229 4230 Level: beginner 4231 4232 Note: 4233 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4234 4235 Fortran Notes: 4236 `points` must be declared with 4237 .vb 4238 PetscInt, pointer :: points(:) 4239 .ve 4240 and is always allocated by the function. 4241 4242 Pass `PETSC_NULL_INTEGER` for `numPoints` if it is not needed 4243 4244 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4245 @*/ 4246 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4247 { 4248 PetscFunctionBeginHot; 4249 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4250 if (numPoints) PetscAssertPointer(numPoints, 4); 4251 if (points) PetscAssertPointer(points, 5); 4252 if (PetscDefined(USE_DEBUG)) { 4253 PetscInt pStart, pEnd; 4254 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4255 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); 4256 } 4257 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4258 PetscFunctionReturn(PETSC_SUCCESS); 4259 } 4260 4261 /*@C 4262 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4263 4264 Not Collective 4265 4266 Input Parameters: 4267 + dm - The `DMPLEX` 4268 . p - The mesh point 4269 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4270 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4271 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4272 4273 Level: beginner 4274 4275 Note: 4276 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4277 4278 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4279 @*/ 4280 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4281 { 4282 PetscFunctionBeginHot; 4283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4284 if (numPoints) *numPoints = 0; 4285 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4286 PetscFunctionReturn(PETSC_SUCCESS); 4287 } 4288 4289 /*@ 4290 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4291 4292 Not Collective 4293 4294 Input Parameter: 4295 . dm - The `DMPLEX` 4296 4297 Output Parameters: 4298 + maxConeSize - The maximum number of in-edges 4299 - maxSupportSize - The maximum number of out-edges 4300 4301 Level: beginner 4302 4303 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4304 @*/ 4305 PetscErrorCode DMPlexGetMaxSizes(DM dm, PeOp PetscInt *maxConeSize, PeOp PetscInt *maxSupportSize) 4306 { 4307 DM_Plex *mesh = (DM_Plex *)dm->data; 4308 4309 PetscFunctionBegin; 4310 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4311 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4312 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4313 PetscFunctionReturn(PETSC_SUCCESS); 4314 } 4315 4316 PetscErrorCode DMSetUp_Plex(DM dm) 4317 { 4318 DM_Plex *mesh = (DM_Plex *)dm->data; 4319 PetscInt size, maxSupportSize; 4320 4321 PetscFunctionBegin; 4322 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4323 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4324 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4325 PetscCall(PetscMalloc1(size, &mesh->cones)); 4326 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4327 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4328 if (maxSupportSize) { 4329 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4330 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4331 PetscCall(PetscMalloc1(size, &mesh->supports)); 4332 } 4333 PetscFunctionReturn(PETSC_SUCCESS); 4334 } 4335 4336 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4337 { 4338 PetscFunctionBegin; 4339 if (subdm) PetscCall(DMClone(dm, subdm)); 4340 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4341 if (subdm) (*subdm)->useNatural = dm->useNatural; 4342 if (dm->useNatural && dm->sfMigration) { 4343 PetscSF sfNatural; 4344 4345 (*subdm)->sfMigration = dm->sfMigration; 4346 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4347 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4348 (*subdm)->sfNatural = sfNatural; 4349 } 4350 PetscFunctionReturn(PETSC_SUCCESS); 4351 } 4352 4353 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4354 { 4355 PetscInt i = 0; 4356 4357 PetscFunctionBegin; 4358 PetscCall(DMClone(dms[0], superdm)); 4359 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4360 (*superdm)->useNatural = PETSC_FALSE; 4361 for (i = 0; i < len; i++) { 4362 if (dms[i]->useNatural && dms[i]->sfMigration) { 4363 PetscSF sfNatural; 4364 4365 (*superdm)->sfMigration = dms[i]->sfMigration; 4366 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4367 (*superdm)->useNatural = PETSC_TRUE; 4368 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4369 (*superdm)->sfNatural = sfNatural; 4370 break; 4371 } 4372 } 4373 PetscFunctionReturn(PETSC_SUCCESS); 4374 } 4375 4376 /*@ 4377 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4378 4379 Not Collective 4380 4381 Input Parameter: 4382 . dm - The `DMPLEX` 4383 4384 Level: beginner 4385 4386 Note: 4387 This should be called after all calls to `DMPlexSetCone()` 4388 4389 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4390 @*/ 4391 PetscErrorCode DMPlexSymmetrize(DM dm) 4392 { 4393 DM_Plex *mesh = (DM_Plex *)dm->data; 4394 PetscInt *offsets; 4395 PetscInt supportSize; 4396 PetscInt pStart, pEnd, p; 4397 4398 PetscFunctionBegin; 4399 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4400 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4401 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4402 /* Calculate support sizes */ 4403 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4404 for (p = pStart; p < pEnd; ++p) { 4405 PetscInt dof, off, c; 4406 4407 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4408 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4409 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4410 } 4411 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4412 /* Calculate supports */ 4413 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4414 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4415 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4416 for (p = pStart; p < pEnd; ++p) { 4417 PetscInt dof, off, c; 4418 4419 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4420 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4421 for (c = off; c < off + dof; ++c) { 4422 const PetscInt q = mesh->cones[c]; 4423 PetscInt offS; 4424 4425 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4426 4427 mesh->supports[offS + offsets[q]] = p; 4428 ++offsets[q]; 4429 } 4430 } 4431 PetscCall(PetscFree(offsets)); 4432 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4433 PetscFunctionReturn(PETSC_SUCCESS); 4434 } 4435 4436 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4437 { 4438 IS stratumIS; 4439 4440 PetscFunctionBegin; 4441 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4442 if (PetscDefined(USE_DEBUG)) { 4443 PetscInt qStart, qEnd, numLevels, level; 4444 PetscBool overlap = PETSC_FALSE; 4445 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4446 for (level = 0; level < numLevels; level++) { 4447 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4448 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4449 overlap = PETSC_TRUE; 4450 break; 4451 } 4452 } 4453 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); 4454 } 4455 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4456 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4457 PetscCall(ISDestroy(&stratumIS)); 4458 PetscFunctionReturn(PETSC_SUCCESS); 4459 } 4460 4461 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4462 { 4463 PetscInt *pMin, *pMax; 4464 PetscInt pStart, pEnd; 4465 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4466 4467 PetscFunctionBegin; 4468 { 4469 DMLabel label2; 4470 4471 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4472 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4473 } 4474 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4475 for (PetscInt p = pStart; p < pEnd; ++p) { 4476 DMPolytopeType ct; 4477 4478 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4479 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4480 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4481 } 4482 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4483 for (PetscInt d = dmin; d <= dmax; ++d) { 4484 pMin[d] = PETSC_INT_MAX; 4485 pMax[d] = PETSC_INT_MIN; 4486 } 4487 for (PetscInt p = pStart; p < pEnd; ++p) { 4488 DMPolytopeType ct; 4489 PetscInt d; 4490 4491 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4492 d = DMPolytopeTypeGetDim(ct); 4493 pMin[d] = PetscMin(p, pMin[d]); 4494 pMax[d] = PetscMax(p, pMax[d]); 4495 } 4496 for (PetscInt d = dmin; d <= dmax; ++d) { 4497 if (pMin[d] > pMax[d]) continue; 4498 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4499 } 4500 PetscCall(PetscFree2(pMin, pMax)); 4501 PetscFunctionReturn(PETSC_SUCCESS); 4502 } 4503 4504 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4505 { 4506 PetscInt pStart, pEnd; 4507 PetscInt numRoots = 0, numLeaves = 0; 4508 4509 PetscFunctionBegin; 4510 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4511 { 4512 /* Initialize roots and count leaves */ 4513 PetscInt sMin = PETSC_INT_MAX; 4514 PetscInt sMax = PETSC_INT_MIN; 4515 PetscInt coneSize, supportSize; 4516 4517 for (PetscInt p = pStart; p < pEnd; ++p) { 4518 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4519 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4520 if (!coneSize && supportSize) { 4521 sMin = PetscMin(p, sMin); 4522 sMax = PetscMax(p, sMax); 4523 ++numRoots; 4524 } else if (!supportSize && coneSize) { 4525 ++numLeaves; 4526 } else if (!supportSize && !coneSize) { 4527 /* Isolated points */ 4528 sMin = PetscMin(p, sMin); 4529 sMax = PetscMax(p, sMax); 4530 } 4531 } 4532 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4533 } 4534 4535 if (numRoots + numLeaves == (pEnd - pStart)) { 4536 PetscInt sMin = PETSC_INT_MAX; 4537 PetscInt sMax = PETSC_INT_MIN; 4538 PetscInt coneSize, supportSize; 4539 4540 for (PetscInt p = pStart; p < pEnd; ++p) { 4541 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4542 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4543 if (!supportSize && coneSize) { 4544 sMin = PetscMin(p, sMin); 4545 sMax = PetscMax(p, sMax); 4546 } 4547 } 4548 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4549 } else { 4550 PetscInt level = 0; 4551 PetscInt qStart, qEnd; 4552 4553 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4554 while (qEnd > qStart) { 4555 PetscInt sMin = PETSC_INT_MAX; 4556 PetscInt sMax = PETSC_INT_MIN; 4557 4558 for (PetscInt q = qStart; q < qEnd; ++q) { 4559 const PetscInt *support; 4560 PetscInt supportSize; 4561 4562 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4563 PetscCall(DMPlexGetSupport(dm, q, &support)); 4564 for (PetscInt s = 0; s < supportSize; ++s) { 4565 sMin = PetscMin(support[s], sMin); 4566 sMax = PetscMax(support[s], sMax); 4567 } 4568 } 4569 PetscCall(DMLabelGetNumValues(label, &level)); 4570 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4571 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4572 } 4573 } 4574 PetscFunctionReturn(PETSC_SUCCESS); 4575 } 4576 4577 /*@ 4578 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4579 4580 Collective 4581 4582 Input Parameter: 4583 . dm - The `DMPLEX` 4584 4585 Level: beginner 4586 4587 Notes: 4588 The strata group all points of the same grade, and this function calculates the strata. This 4589 grade can be seen as the height (or depth) of the point in the DAG. 4590 4591 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4592 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4593 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4594 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4595 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4596 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4597 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4598 4599 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4600 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4601 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 4602 to interpolate only that one (e0), so that 4603 .vb 4604 cone(c0) = {e0, v2} 4605 cone(e0) = {v0, v1} 4606 .ve 4607 If `DMPlexStratify()` is run on this mesh, it will give depths 4608 .vb 4609 depth 0 = {v0, v1, v2} 4610 depth 1 = {e0, c0} 4611 .ve 4612 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4613 4614 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4615 4616 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4617 @*/ 4618 PetscErrorCode DMPlexStratify(DM dm) 4619 { 4620 DM_Plex *mesh = (DM_Plex *)dm->data; 4621 DMLabel label; 4622 PetscBool flg = PETSC_FALSE; 4623 4624 PetscFunctionBegin; 4625 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4626 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4627 4628 // Create depth label 4629 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4630 PetscCall(DMCreateLabel(dm, "depth")); 4631 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4632 4633 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4634 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4635 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4636 4637 { /* just in case there is an empty process */ 4638 PetscInt numValues, maxValues = 0, v; 4639 4640 PetscCall(DMLabelGetNumValues(label, &numValues)); 4641 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4642 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4643 } 4644 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4645 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4646 PetscFunctionReturn(PETSC_SUCCESS); 4647 } 4648 4649 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4650 { 4651 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4652 PetscInt dim, depth, pheight, coneSize; 4653 PetscBool preferTensor; 4654 4655 PetscFunctionBeginHot; 4656 PetscCall(DMGetDimension(dm, &dim)); 4657 PetscCall(DMPlexGetDepth(dm, &depth)); 4658 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4659 PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor)); 4660 pheight = depth - pdepth; 4661 if (depth <= 1) { 4662 switch (pdepth) { 4663 case 0: 4664 ct = DM_POLYTOPE_POINT; 4665 break; 4666 case 1: 4667 switch (coneSize) { 4668 case 2: 4669 ct = DM_POLYTOPE_SEGMENT; 4670 break; 4671 case 3: 4672 ct = DM_POLYTOPE_TRIANGLE; 4673 break; 4674 case 4: 4675 switch (dim) { 4676 case 2: 4677 ct = DM_POLYTOPE_QUADRILATERAL; 4678 break; 4679 case 3: 4680 ct = DM_POLYTOPE_TETRAHEDRON; 4681 break; 4682 default: 4683 break; 4684 } 4685 break; 4686 case 5: 4687 ct = DM_POLYTOPE_PYRAMID; 4688 break; 4689 case 6: 4690 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4691 break; 4692 case 8: 4693 ct = DM_POLYTOPE_HEXAHEDRON; 4694 break; 4695 default: 4696 break; 4697 } 4698 } 4699 } else { 4700 if (pdepth == 0) { 4701 ct = DM_POLYTOPE_POINT; 4702 } else if (pheight == 0) { 4703 switch (dim) { 4704 case 1: 4705 switch (coneSize) { 4706 case 2: 4707 ct = DM_POLYTOPE_SEGMENT; 4708 break; 4709 default: 4710 break; 4711 } 4712 break; 4713 case 2: 4714 switch (coneSize) { 4715 case 3: 4716 ct = DM_POLYTOPE_TRIANGLE; 4717 break; 4718 case 4: 4719 ct = DM_POLYTOPE_QUADRILATERAL; 4720 break; 4721 default: 4722 break; 4723 } 4724 break; 4725 case 3: 4726 switch (coneSize) { 4727 case 4: 4728 ct = DM_POLYTOPE_TETRAHEDRON; 4729 break; 4730 case 5: { 4731 const PetscInt *cone; 4732 PetscInt faceConeSize; 4733 4734 PetscCall(DMPlexGetCone(dm, p, &cone)); 4735 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4736 switch (faceConeSize) { 4737 case 3: 4738 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4739 break; 4740 case 4: 4741 ct = DM_POLYTOPE_PYRAMID; 4742 break; 4743 } 4744 } break; 4745 case 6: 4746 ct = DM_POLYTOPE_HEXAHEDRON; 4747 break; 4748 default: 4749 break; 4750 } 4751 break; 4752 default: 4753 break; 4754 } 4755 } else if (pheight > 0) { 4756 switch (coneSize) { 4757 case 2: 4758 ct = DM_POLYTOPE_SEGMENT; 4759 break; 4760 case 3: 4761 ct = DM_POLYTOPE_TRIANGLE; 4762 break; 4763 case 4: 4764 ct = DM_POLYTOPE_QUADRILATERAL; 4765 break; 4766 default: 4767 break; 4768 } 4769 } 4770 } 4771 *pt = ct; 4772 PetscFunctionReturn(PETSC_SUCCESS); 4773 } 4774 4775 /*@ 4776 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4777 4778 Collective 4779 4780 Input Parameter: 4781 . dm - The `DMPLEX` 4782 4783 Level: developer 4784 4785 Note: 4786 This function is normally called automatically when a cell type is requested. It creates an 4787 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4788 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4789 4790 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4791 4792 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4793 @*/ 4794 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4795 { 4796 DM_Plex *mesh; 4797 DMLabel ctLabel; 4798 PetscInt pStart, pEnd, p; 4799 4800 PetscFunctionBegin; 4801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4802 mesh = (DM_Plex *)dm->data; 4803 PetscCall(DMCreateLabel(dm, "celltype")); 4804 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4805 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4806 PetscCall(PetscFree(mesh->cellTypes)); 4807 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4808 for (p = pStart; p < pEnd; ++p) { 4809 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4810 PetscInt pdepth; 4811 4812 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4813 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4814 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]); 4815 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4816 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4817 } 4818 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4819 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4820 PetscFunctionReturn(PETSC_SUCCESS); 4821 } 4822 4823 /*@C 4824 DMPlexGetJoin - Get an array for the join of the set of points 4825 4826 Not Collective 4827 4828 Input Parameters: 4829 + dm - The `DMPLEX` object 4830 . numPoints - The number of input points for the join 4831 - points - The input points 4832 4833 Output Parameters: 4834 + numCoveredPoints - The number of points in the join 4835 - coveredPoints - The points in the join 4836 4837 Level: intermediate 4838 4839 Note: 4840 Currently, this is restricted to a single level join 4841 4842 Fortran Notes: 4843 `converedPoints` must be declared with 4844 .vb 4845 PetscInt, pointer :: coveredPints(:) 4846 .ve 4847 4848 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4849 @*/ 4850 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4851 { 4852 DM_Plex *mesh = (DM_Plex *)dm->data; 4853 PetscInt *join[2]; 4854 PetscInt joinSize, i = 0; 4855 PetscInt dof, off, p, c, m; 4856 PetscInt maxSupportSize; 4857 4858 PetscFunctionBegin; 4859 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4860 PetscAssertPointer(points, 3); 4861 PetscAssertPointer(numCoveredPoints, 4); 4862 PetscAssertPointer(coveredPoints, 5); 4863 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4864 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4865 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4866 /* Copy in support of first point */ 4867 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4868 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4869 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4870 /* Check each successive support */ 4871 for (p = 1; p < numPoints; ++p) { 4872 PetscInt newJoinSize = 0; 4873 4874 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4875 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4876 for (c = 0; c < dof; ++c) { 4877 const PetscInt point = mesh->supports[off + c]; 4878 4879 for (m = 0; m < joinSize; ++m) { 4880 if (point == join[i][m]) { 4881 join[1 - i][newJoinSize++] = point; 4882 break; 4883 } 4884 } 4885 } 4886 joinSize = newJoinSize; 4887 i = 1 - i; 4888 } 4889 *numCoveredPoints = joinSize; 4890 *coveredPoints = join[i]; 4891 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4892 PetscFunctionReturn(PETSC_SUCCESS); 4893 } 4894 4895 /*@C 4896 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4897 4898 Not Collective 4899 4900 Input Parameters: 4901 + dm - The `DMPLEX` object 4902 . numPoints - The number of input points for the join 4903 - points - The input points 4904 4905 Output Parameters: 4906 + numCoveredPoints - The number of points in the join 4907 - coveredPoints - The points in the join 4908 4909 Level: intermediate 4910 4911 Fortran Notes: 4912 `converedPoints` must be declared with 4913 .vb 4914 PetscInt, pointer :: coveredPoints(:) 4915 .ve 4916 4917 Pass `PETSC_NULL_INTEGER` for `numCoveredPoints` if it is not needed 4918 4919 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4920 @*/ 4921 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4922 { 4923 PetscFunctionBegin; 4924 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4925 if (points) PetscAssertPointer(points, 3); 4926 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4927 PetscAssertPointer(coveredPoints, 5); 4928 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4929 if (numCoveredPoints) *numCoveredPoints = 0; 4930 PetscFunctionReturn(PETSC_SUCCESS); 4931 } 4932 4933 /*@C 4934 DMPlexGetFullJoin - Get an array for the join of the set of points 4935 4936 Not Collective 4937 4938 Input Parameters: 4939 + dm - The `DMPLEX` object 4940 . numPoints - The number of input points for the join 4941 - points - The input points, its length is `numPoints` 4942 4943 Output Parameters: 4944 + numCoveredPoints - The number of points in the join 4945 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4946 4947 Level: intermediate 4948 4949 Fortran Notes: 4950 .vb 4951 PetscInt, pointer :: coveredPints(:) 4952 .ve 4953 4954 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4955 @*/ 4956 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4957 { 4958 PetscInt *offsets, **closures; 4959 PetscInt *join[2]; 4960 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4961 PetscInt p, d, c, m, ms; 4962 4963 PetscFunctionBegin; 4964 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4965 PetscAssertPointer(points, 3); 4966 PetscAssertPointer(numCoveredPoints, 4); 4967 PetscAssertPointer(coveredPoints, 5); 4968 4969 PetscCall(DMPlexGetDepth(dm, &depth)); 4970 PetscCall(PetscCalloc1(numPoints, &closures)); 4971 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4972 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4973 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4974 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4975 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4976 4977 for (p = 0; p < numPoints; ++p) { 4978 PetscInt closureSize; 4979 4980 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4981 4982 offsets[p * (depth + 2) + 0] = 0; 4983 for (d = 0; d < depth + 1; ++d) { 4984 PetscInt pStart, pEnd, i; 4985 4986 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4987 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4988 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4989 offsets[p * (depth + 2) + d + 1] = i; 4990 break; 4991 } 4992 } 4993 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4994 } 4995 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); 4996 } 4997 for (d = 0; d < depth + 1; ++d) { 4998 PetscInt dof; 4999 5000 /* Copy in support of first point */ 5001 dof = offsets[d + 1] - offsets[d]; 5002 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 5003 /* Check each successive cone */ 5004 for (p = 1; p < numPoints && joinSize; ++p) { 5005 PetscInt newJoinSize = 0; 5006 5007 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 5008 for (c = 0; c < dof; ++c) { 5009 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 5010 5011 for (m = 0; m < joinSize; ++m) { 5012 if (point == join[i][m]) { 5013 join[1 - i][newJoinSize++] = point; 5014 break; 5015 } 5016 } 5017 } 5018 joinSize = newJoinSize; 5019 i = 1 - i; 5020 } 5021 if (joinSize) break; 5022 } 5023 *numCoveredPoints = joinSize; 5024 *coveredPoints = join[i]; 5025 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 5026 PetscCall(PetscFree(closures)); 5027 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 5028 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 5029 PetscFunctionReturn(PETSC_SUCCESS); 5030 } 5031 5032 /*@C 5033 DMPlexGetMeet - Get an array for the meet of the set of points 5034 5035 Not Collective 5036 5037 Input Parameters: 5038 + dm - The `DMPLEX` object 5039 . numPoints - The number of input points for the meet 5040 - points - The input points, of length `numPoints` 5041 5042 Output Parameters: 5043 + numCoveringPoints - The number of points in the meet 5044 - coveringPoints - The points in the meet, of length `numCoveringPoints` 5045 5046 Level: intermediate 5047 5048 Note: 5049 Currently, this is restricted to a single level meet 5050 5051 Fortran Note: 5052 `coveringPoints` must be declared with 5053 .vb 5054 PetscInt, pointer :: coveringPoints(:) 5055 .ve 5056 5057 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5058 @*/ 5059 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 5060 { 5061 DM_Plex *mesh = (DM_Plex *)dm->data; 5062 PetscInt *meet[2]; 5063 PetscInt meetSize, i = 0; 5064 PetscInt dof, off, p, c, m; 5065 PetscInt maxConeSize; 5066 5067 PetscFunctionBegin; 5068 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5069 PetscAssertPointer(points, 3); 5070 PetscAssertPointer(numCoveringPoints, 4); 5071 PetscAssertPointer(coveringPoints, 5); 5072 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 5073 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 5074 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 5075 /* Copy in cone of first point */ 5076 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 5077 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 5078 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5079 /* Check each successive cone */ 5080 for (p = 1; p < numPoints; ++p) { 5081 PetscInt newMeetSize = 0; 5082 5083 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5084 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5085 for (c = 0; c < dof; ++c) { 5086 const PetscInt point = mesh->cones[off + c]; 5087 5088 for (m = 0; m < meetSize; ++m) { 5089 if (point == meet[i][m]) { 5090 meet[1 - i][newMeetSize++] = point; 5091 break; 5092 } 5093 } 5094 } 5095 meetSize = newMeetSize; 5096 i = 1 - i; 5097 } 5098 *numCoveringPoints = meetSize; 5099 *coveringPoints = meet[i]; 5100 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5101 PetscFunctionReturn(PETSC_SUCCESS); 5102 } 5103 5104 /*@C 5105 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5106 5107 Not Collective 5108 5109 Input Parameters: 5110 + dm - The `DMPLEX` object 5111 . numPoints - The number of input points for the meet 5112 - points - The input points 5113 5114 Output Parameters: 5115 + numCoveredPoints - The number of points in the meet 5116 - coveredPoints - The points in the meet 5117 5118 Level: intermediate 5119 5120 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5121 @*/ 5122 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5123 { 5124 PetscFunctionBegin; 5125 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5126 if (points) PetscAssertPointer(points, 3); 5127 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5128 PetscAssertPointer(coveredPoints, 5); 5129 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5130 if (numCoveredPoints) *numCoveredPoints = 0; 5131 PetscFunctionReturn(PETSC_SUCCESS); 5132 } 5133 5134 /*@C 5135 DMPlexGetFullMeet - Get an array for the meet of the set of points 5136 5137 Not Collective 5138 5139 Input Parameters: 5140 + dm - The `DMPLEX` object 5141 . numPoints - The number of input points for the meet 5142 - points - The input points, of length `numPoints` 5143 5144 Output Parameters: 5145 + numCoveredPoints - The number of points in the meet 5146 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5147 5148 Level: intermediate 5149 5150 Fortran Notes: 5151 `coveredPoints` must be declared with 5152 .vb 5153 PetscInt, pointer :: coveredPoints(:) 5154 .ve 5155 5156 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5157 @*/ 5158 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5159 { 5160 PetscInt *offsets, **closures; 5161 PetscInt *meet[2]; 5162 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5163 PetscInt p, h, c, m, mc; 5164 5165 PetscFunctionBegin; 5166 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5167 PetscAssertPointer(points, 3); 5168 PetscAssertPointer(numCoveredPoints, 4); 5169 PetscAssertPointer(coveredPoints, 5); 5170 5171 PetscCall(DMPlexGetDepth(dm, &height)); 5172 PetscCall(PetscMalloc1(numPoints, &closures)); 5173 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5174 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5175 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5176 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5177 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5178 5179 for (p = 0; p < numPoints; ++p) { 5180 PetscInt closureSize; 5181 5182 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5183 5184 offsets[p * (height + 2) + 0] = 0; 5185 for (h = 0; h < height + 1; ++h) { 5186 PetscInt pStart, pEnd, i; 5187 5188 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5189 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5190 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5191 offsets[p * (height + 2) + h + 1] = i; 5192 break; 5193 } 5194 } 5195 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5196 } 5197 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); 5198 } 5199 for (h = 0; h < height + 1; ++h) { 5200 PetscInt dof; 5201 5202 /* Copy in cone of first point */ 5203 dof = offsets[h + 1] - offsets[h]; 5204 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5205 /* Check each successive cone */ 5206 for (p = 1; p < numPoints && meetSize; ++p) { 5207 PetscInt newMeetSize = 0; 5208 5209 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5210 for (c = 0; c < dof; ++c) { 5211 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5212 5213 for (m = 0; m < meetSize; ++m) { 5214 if (point == meet[i][m]) { 5215 meet[1 - i][newMeetSize++] = point; 5216 break; 5217 } 5218 } 5219 } 5220 meetSize = newMeetSize; 5221 i = 1 - i; 5222 } 5223 if (meetSize) break; 5224 } 5225 *numCoveredPoints = meetSize; 5226 *coveredPoints = meet[i]; 5227 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5228 PetscCall(PetscFree(closures)); 5229 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5230 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5231 PetscFunctionReturn(PETSC_SUCCESS); 5232 } 5233 5234 /*@ 5235 DMPlexEqual - Determine if two `DM` have the same topology 5236 5237 Not Collective 5238 5239 Input Parameters: 5240 + dmA - A `DMPLEX` object 5241 - dmB - A `DMPLEX` object 5242 5243 Output Parameter: 5244 . equal - `PETSC_TRUE` if the topologies are identical 5245 5246 Level: intermediate 5247 5248 Note: 5249 We are not solving graph isomorphism, so we do not permute. 5250 5251 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5252 @*/ 5253 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5254 { 5255 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5256 5257 PetscFunctionBegin; 5258 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5259 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5260 PetscAssertPointer(equal, 3); 5261 5262 *equal = PETSC_FALSE; 5263 PetscCall(DMPlexGetDepth(dmA, &depth)); 5264 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5265 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5266 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5267 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5268 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5269 for (p = pStart; p < pEnd; ++p) { 5270 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5271 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5272 5273 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5274 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5275 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5276 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5277 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5278 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5279 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5280 for (c = 0; c < coneSize; ++c) { 5281 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5282 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5283 } 5284 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5285 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5286 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5287 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5288 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5289 for (s = 0; s < supportSize; ++s) { 5290 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5291 } 5292 } 5293 *equal = PETSC_TRUE; 5294 PetscFunctionReturn(PETSC_SUCCESS); 5295 } 5296 5297 /*@ 5298 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5299 5300 Not Collective 5301 5302 Input Parameters: 5303 + dm - The `DMPLEX` 5304 . cellDim - The cell dimension 5305 - numCorners - The number of vertices on a cell 5306 5307 Output Parameter: 5308 . numFaceVertices - The number of vertices on a face 5309 5310 Level: developer 5311 5312 Note: 5313 Of course this can only work for a restricted set of symmetric shapes 5314 5315 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5316 @*/ 5317 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5318 { 5319 MPI_Comm comm; 5320 5321 PetscFunctionBegin; 5322 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5323 PetscAssertPointer(numFaceVertices, 4); 5324 switch (cellDim) { 5325 case 0: 5326 *numFaceVertices = 0; 5327 break; 5328 case 1: 5329 *numFaceVertices = 1; 5330 break; 5331 case 2: 5332 switch (numCorners) { 5333 case 3: /* triangle */ 5334 *numFaceVertices = 2; /* Edge has 2 vertices */ 5335 break; 5336 case 4: /* quadrilateral */ 5337 *numFaceVertices = 2; /* Edge has 2 vertices */ 5338 break; 5339 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5340 *numFaceVertices = 3; /* Edge has 3 vertices */ 5341 break; 5342 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5343 *numFaceVertices = 3; /* Edge has 3 vertices */ 5344 break; 5345 default: 5346 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5347 } 5348 break; 5349 case 3: 5350 switch (numCorners) { 5351 case 4: /* tetradehdron */ 5352 *numFaceVertices = 3; /* Face has 3 vertices */ 5353 break; 5354 case 6: /* tet cohesive cells */ 5355 *numFaceVertices = 4; /* Face has 4 vertices */ 5356 break; 5357 case 8: /* hexahedron */ 5358 *numFaceVertices = 4; /* Face has 4 vertices */ 5359 break; 5360 case 9: /* tet cohesive Lagrange cells */ 5361 *numFaceVertices = 6; /* Face has 6 vertices */ 5362 break; 5363 case 10: /* quadratic tetrahedron */ 5364 *numFaceVertices = 6; /* Face has 6 vertices */ 5365 break; 5366 case 12: /* hex cohesive Lagrange cells */ 5367 *numFaceVertices = 6; /* Face has 6 vertices */ 5368 break; 5369 case 18: /* quadratic tet cohesive Lagrange cells */ 5370 *numFaceVertices = 6; /* Face has 6 vertices */ 5371 break; 5372 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5373 *numFaceVertices = 9; /* Face has 9 vertices */ 5374 break; 5375 default: 5376 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5377 } 5378 break; 5379 default: 5380 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5381 } 5382 PetscFunctionReturn(PETSC_SUCCESS); 5383 } 5384 5385 /*@ 5386 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5387 5388 Not Collective 5389 5390 Input Parameter: 5391 . dm - The `DMPLEX` object 5392 5393 Output Parameter: 5394 . depthLabel - The `DMLabel` recording point depth 5395 5396 Level: developer 5397 5398 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5399 @*/ 5400 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5401 { 5402 PetscFunctionBegin; 5403 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5404 PetscAssertPointer(depthLabel, 2); 5405 *depthLabel = dm->depthLabel; 5406 PetscFunctionReturn(PETSC_SUCCESS); 5407 } 5408 5409 /*@ 5410 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5411 5412 Not Collective 5413 5414 Input Parameter: 5415 . dm - The `DMPLEX` object 5416 5417 Output Parameter: 5418 . depth - The number of strata (breadth first levels) in the DAG 5419 5420 Level: developer 5421 5422 Notes: 5423 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5424 5425 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5426 5427 An empty mesh gives -1. 5428 5429 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5430 @*/ 5431 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5432 { 5433 DM_Plex *mesh = (DM_Plex *)dm->data; 5434 DMLabel label; 5435 PetscInt d = -1; 5436 5437 PetscFunctionBegin; 5438 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5439 PetscAssertPointer(depth, 2); 5440 if (mesh->tr) { 5441 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5442 } else { 5443 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5444 // Allow missing depths 5445 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5446 *depth = d; 5447 } 5448 PetscFunctionReturn(PETSC_SUCCESS); 5449 } 5450 5451 /*@ 5452 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5453 5454 Not Collective 5455 5456 Input Parameters: 5457 + dm - The `DMPLEX` object 5458 - depth - The requested depth 5459 5460 Output Parameters: 5461 + start - The first point at this `depth` 5462 - end - One beyond the last point at this `depth` 5463 5464 Level: developer 5465 5466 Notes: 5467 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5468 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5469 higher dimension, e.g., "edges". 5470 5471 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5472 @*/ 5473 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PeOp PetscInt *start, PeOp PetscInt *end) 5474 { 5475 DM_Plex *mesh = (DM_Plex *)dm->data; 5476 DMLabel label; 5477 PetscInt pStart, pEnd; 5478 5479 PetscFunctionBegin; 5480 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5481 if (start) { 5482 PetscAssertPointer(start, 3); 5483 *start = 0; 5484 } 5485 if (end) { 5486 PetscAssertPointer(end, 4); 5487 *end = 0; 5488 } 5489 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5490 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5491 if (depth < 0) { 5492 if (start) *start = pStart; 5493 if (end) *end = pEnd; 5494 PetscFunctionReturn(PETSC_SUCCESS); 5495 } 5496 if (mesh->tr) { 5497 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5498 } else { 5499 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5500 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5501 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5502 } 5503 PetscFunctionReturn(PETSC_SUCCESS); 5504 } 5505 5506 /*@ 5507 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5508 5509 Not Collective 5510 5511 Input Parameters: 5512 + dm - The `DMPLEX` object 5513 - height - The requested height 5514 5515 Output Parameters: 5516 + start - The first point at this `height` 5517 - end - One beyond the last point at this `height` 5518 5519 Level: developer 5520 5521 Notes: 5522 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5523 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5524 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5525 5526 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5527 @*/ 5528 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PeOp PetscInt *start, PeOp PetscInt *end) 5529 { 5530 DMLabel label; 5531 PetscInt depth, pStart, pEnd; 5532 5533 PetscFunctionBegin; 5534 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5535 if (start) { 5536 PetscAssertPointer(start, 3); 5537 *start = 0; 5538 } 5539 if (end) { 5540 PetscAssertPointer(end, 4); 5541 *end = 0; 5542 } 5543 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5544 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5545 if (height < 0) { 5546 if (start) *start = pStart; 5547 if (end) *end = pEnd; 5548 PetscFunctionReturn(PETSC_SUCCESS); 5549 } 5550 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5551 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5552 else PetscCall(DMGetDimension(dm, &depth)); 5553 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5554 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5555 PetscFunctionReturn(PETSC_SUCCESS); 5556 } 5557 5558 /*@ 5559 DMPlexGetPointDepth - Get the `depth` of a given point 5560 5561 Not Collective 5562 5563 Input Parameters: 5564 + dm - The `DMPLEX` object 5565 - point - The point 5566 5567 Output Parameter: 5568 . depth - The depth of the `point` 5569 5570 Level: intermediate 5571 5572 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5573 @*/ 5574 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5575 { 5576 PetscFunctionBegin; 5577 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5578 PetscAssertPointer(depth, 3); 5579 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5580 PetscFunctionReturn(PETSC_SUCCESS); 5581 } 5582 5583 /*@ 5584 DMPlexGetPointHeight - Get the `height` of a given point 5585 5586 Not Collective 5587 5588 Input Parameters: 5589 + dm - The `DMPLEX` object 5590 - point - The point 5591 5592 Output Parameter: 5593 . height - The height of the `point` 5594 5595 Level: intermediate 5596 5597 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5598 @*/ 5599 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5600 { 5601 PetscInt n, pDepth; 5602 5603 PetscFunctionBegin; 5604 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5605 PetscAssertPointer(height, 3); 5606 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5607 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5608 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5609 PetscFunctionReturn(PETSC_SUCCESS); 5610 } 5611 5612 /*@ 5613 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5614 5615 Not Collective 5616 5617 Input Parameter: 5618 . dm - The `DMPLEX` object 5619 5620 Output Parameter: 5621 . celltypeLabel - The `DMLabel` recording cell polytope type 5622 5623 Level: developer 5624 5625 Note: 5626 This function will trigger automatica computation of cell types. This can be disabled by calling 5627 `DMCreateLabel`(dm, "celltype") beforehand. 5628 5629 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5630 @*/ 5631 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5632 { 5633 PetscFunctionBegin; 5634 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5635 PetscAssertPointer(celltypeLabel, 2); 5636 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5637 *celltypeLabel = dm->celltypeLabel; 5638 PetscFunctionReturn(PETSC_SUCCESS); 5639 } 5640 5641 /*@ 5642 DMPlexGetCellType - Get the polytope type of a given cell 5643 5644 Not Collective 5645 5646 Input Parameters: 5647 + dm - The `DMPLEX` object 5648 - cell - The cell 5649 5650 Output Parameter: 5651 . celltype - The polytope type of the cell 5652 5653 Level: intermediate 5654 5655 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5656 @*/ 5657 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5658 { 5659 DM_Plex *mesh = (DM_Plex *)dm->data; 5660 DMLabel label; 5661 PetscInt ct; 5662 5663 PetscFunctionBegin; 5664 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5665 PetscAssertPointer(celltype, 3); 5666 if (mesh->tr) { 5667 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5668 } else { 5669 PetscInt pStart, pEnd; 5670 5671 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5672 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5673 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5674 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5675 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5676 for (PetscInt p = pStart; p < pEnd; p++) { 5677 PetscCall(DMLabelGetValue(label, p, &ct)); 5678 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5679 } 5680 } 5681 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5682 if (PetscDefined(USE_DEBUG)) { 5683 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5684 PetscCall(DMLabelGetValue(label, cell, &ct)); 5685 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5686 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5687 } 5688 } 5689 PetscFunctionReturn(PETSC_SUCCESS); 5690 } 5691 5692 /*@ 5693 DMPlexSetCellType - Set the polytope type of a given cell 5694 5695 Not Collective 5696 5697 Input Parameters: 5698 + dm - The `DMPLEX` object 5699 . cell - The cell 5700 - celltype - The polytope type of the cell 5701 5702 Level: advanced 5703 5704 Note: 5705 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5706 is executed. This function will override the computed type. However, if automatic classification will not succeed 5707 and a user wants to manually specify all types, the classification must be disabled by calling 5708 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5709 5710 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5711 @*/ 5712 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5713 { 5714 DM_Plex *mesh = (DM_Plex *)dm->data; 5715 DMLabel label; 5716 PetscInt pStart, pEnd; 5717 5718 PetscFunctionBegin; 5719 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5720 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5721 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5722 PetscCall(DMLabelSetValue(label, cell, celltype)); 5723 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5724 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5725 PetscFunctionReturn(PETSC_SUCCESS); 5726 } 5727 5728 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5729 { 5730 PetscSection section; 5731 PetscInt maxHeight; 5732 const char *prefix; 5733 5734 PetscFunctionBegin; 5735 PetscCall(DMClone(dm, cdm)); 5736 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5737 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5738 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5739 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5740 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5741 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5742 PetscCall(DMSetLocalSection(*cdm, section)); 5743 PetscCall(PetscSectionDestroy(§ion)); 5744 5745 PetscCall(DMSetNumFields(*cdm, 1)); 5746 PetscCall(DMCreateDS(*cdm)); 5747 (*cdm)->cloneOpts = PETSC_TRUE; 5748 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5749 PetscFunctionReturn(PETSC_SUCCESS); 5750 } 5751 5752 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5753 { 5754 Vec coordsLocal, cellCoordsLocal; 5755 DM coordsDM, cellCoordsDM; 5756 5757 PetscFunctionBegin; 5758 *field = NULL; 5759 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5760 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5761 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5762 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5763 if (coordsLocal && coordsDM) { 5764 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5765 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5766 } 5767 PetscFunctionReturn(PETSC_SUCCESS); 5768 } 5769 5770 /*@ 5771 DMPlexGetConeSection - Return a section which describes the layout of cone data 5772 5773 Not Collective 5774 5775 Input Parameter: 5776 . dm - The `DMPLEX` object 5777 5778 Output Parameter: 5779 . section - The `PetscSection` object 5780 5781 Level: developer 5782 5783 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5784 @*/ 5785 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5786 { 5787 DM_Plex *mesh = (DM_Plex *)dm->data; 5788 5789 PetscFunctionBegin; 5790 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5791 if (section) *section = mesh->coneSection; 5792 PetscFunctionReturn(PETSC_SUCCESS); 5793 } 5794 5795 /*@ 5796 DMPlexGetSupportSection - Return a section which describes the layout of support data 5797 5798 Not Collective 5799 5800 Input Parameter: 5801 . dm - The `DMPLEX` object 5802 5803 Output Parameter: 5804 . section - The `PetscSection` object 5805 5806 Level: developer 5807 5808 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5809 @*/ 5810 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5811 { 5812 DM_Plex *mesh = (DM_Plex *)dm->data; 5813 5814 PetscFunctionBegin; 5815 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5816 if (section) *section = mesh->supportSection; 5817 PetscFunctionReturn(PETSC_SUCCESS); 5818 } 5819 5820 /*@C 5821 DMPlexGetCones - Return cone data 5822 5823 Not Collective 5824 5825 Input Parameter: 5826 . dm - The `DMPLEX` object 5827 5828 Output Parameter: 5829 . cones - The cone for each point 5830 5831 Level: developer 5832 5833 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5834 @*/ 5835 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5836 { 5837 DM_Plex *mesh = (DM_Plex *)dm->data; 5838 5839 PetscFunctionBegin; 5840 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5841 if (cones) *cones = mesh->cones; 5842 PetscFunctionReturn(PETSC_SUCCESS); 5843 } 5844 5845 /*@C 5846 DMPlexGetConeOrientations - Return cone orientation data 5847 5848 Not Collective 5849 5850 Input Parameter: 5851 . dm - The `DMPLEX` object 5852 5853 Output Parameter: 5854 . coneOrientations - The array of cone orientations for all points 5855 5856 Level: developer 5857 5858 Notes: 5859 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5860 as returned by `DMPlexGetConeOrientation()`. 5861 5862 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5863 5864 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5865 @*/ 5866 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5867 { 5868 DM_Plex *mesh = (DM_Plex *)dm->data; 5869 5870 PetscFunctionBegin; 5871 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5872 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5873 PetscFunctionReturn(PETSC_SUCCESS); 5874 } 5875 5876 /* FEM Support */ 5877 5878 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5879 { 5880 PetscInt depth; 5881 5882 PetscFunctionBegin; 5883 PetscCall(DMPlexGetDepth(plex, &depth)); 5884 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5885 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5886 PetscFunctionReturn(PETSC_SUCCESS); 5887 } 5888 5889 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5890 { 5891 PetscInt depth; 5892 5893 PetscFunctionBegin; 5894 PetscCall(DMPlexGetDepth(plex, &depth)); 5895 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5896 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5897 PetscFunctionReturn(PETSC_SUCCESS); 5898 } 5899 5900 /* 5901 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5902 representing a line in the section. 5903 */ 5904 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5905 { 5906 PetscObject obj; 5907 PetscClassId id; 5908 PetscFE fe = NULL; 5909 5910 PetscFunctionBeginHot; 5911 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5912 PetscCall(DMGetField(dm, field, NULL, &obj)); 5913 PetscCall(PetscObjectGetClassId(obj, &id)); 5914 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5915 5916 if (!fe) { 5917 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5918 /* An order k SEM disc has k-1 dofs on an edge */ 5919 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5920 *k = *k / *Nc + 1; 5921 } else { 5922 PetscInt dual_space_size, dim; 5923 PetscDualSpace dsp; 5924 5925 PetscCall(DMGetDimension(dm, &dim)); 5926 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5927 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5928 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5929 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5930 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5931 } 5932 PetscFunctionReturn(PETSC_SUCCESS); 5933 } 5934 5935 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5936 { 5937 PetscFunctionBeginHot; 5938 if (tensor) { 5939 *dof = PetscPowInt(k + 1, dim); 5940 } else { 5941 switch (dim) { 5942 case 1: 5943 *dof = k + 1; 5944 break; 5945 case 2: 5946 *dof = ((k + 1) * (k + 2)) / 2; 5947 break; 5948 case 3: 5949 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5950 break; 5951 default: 5952 *dof = 0; 5953 } 5954 } 5955 PetscFunctionReturn(PETSC_SUCCESS); 5956 } 5957 5958 /*@ 5959 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5960 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5961 section provided (or the section of the `DM`). 5962 5963 Input Parameters: 5964 + dm - The `DM` 5965 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5966 - section - The `PetscSection` to reorder, or `NULL` for the default section 5967 5968 Example: 5969 A typical interpolated single-quad mesh might order points as 5970 .vb 5971 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5972 5973 v4 -- e6 -- v3 5974 | | 5975 e7 c0 e8 5976 | | 5977 v1 -- e5 -- v2 5978 .ve 5979 5980 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5981 dofs in the order of points, e.g., 5982 .vb 5983 c0 -> [0,1,2,3] 5984 v1 -> [4] 5985 ... 5986 e5 -> [8, 9] 5987 .ve 5988 5989 which corresponds to the dofs 5990 .vb 5991 6 10 11 7 5992 13 2 3 15 5993 12 0 1 14 5994 4 8 9 5 5995 .ve 5996 5997 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5998 .vb 5999 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 6000 .ve 6001 6002 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 6003 .vb 6004 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 6005 .ve 6006 6007 Level: developer 6008 6009 Notes: 6010 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 6011 degree of the basis. 6012 6013 This is required to run with libCEED. 6014 6015 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 6016 @*/ 6017 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 6018 { 6019 DMLabel label; 6020 PetscInt dim, depth = -1, eStart = -1, Nf; 6021 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 6022 6023 PetscFunctionBegin; 6024 PetscCall(DMGetDimension(dm, &dim)); 6025 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 6026 if (point < 0) { 6027 PetscInt sStart, sEnd; 6028 6029 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6030 point = sEnd - sStart ? sStart : point; 6031 } 6032 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6033 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6034 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6035 if (depth == 1) { 6036 eStart = point; 6037 } else if (depth == dim) { 6038 const PetscInt *cone; 6039 6040 PetscCall(DMPlexGetCone(dm, point, &cone)); 6041 if (dim == 2) eStart = cone[0]; 6042 else if (dim == 3) { 6043 const PetscInt *cone2; 6044 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6045 eStart = cone2[0]; 6046 } 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); 6047 } 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); 6048 6049 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6050 for (PetscInt d = 1; d <= dim; d++) { 6051 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6052 PetscInt *perm; 6053 6054 for (f = 0; f < Nf; ++f) { 6055 PetscInt dof; 6056 6057 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6058 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6059 if (!continuous && d < dim) continue; 6060 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6061 size += dof * Nc; 6062 } 6063 PetscCall(PetscMalloc1(size, &perm)); 6064 for (f = 0; f < Nf; ++f) { 6065 switch (d) { 6066 case 1: 6067 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6068 if (!continuous && d < dim) continue; 6069 /* 6070 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6071 We want [ vtx0; edge of length k-1; vtx1 ] 6072 */ 6073 if (continuous) { 6074 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6075 for (i = 0; i < k - 1; i++) 6076 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6077 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6078 foffset = offset; 6079 } else { 6080 PetscInt dof; 6081 6082 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6083 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6084 foffset = offset; 6085 } 6086 break; 6087 case 2: 6088 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6089 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6090 if (!continuous && d < dim) continue; 6091 /* The SEM order is 6092 6093 v_lb, {e_b}, v_rb, 6094 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6095 v_lt, reverse {e_t}, v_rt 6096 */ 6097 if (continuous) { 6098 const PetscInt of = 0; 6099 const PetscInt oeb = of + PetscSqr(k - 1); 6100 const PetscInt oer = oeb + (k - 1); 6101 const PetscInt oet = oer + (k - 1); 6102 const PetscInt oel = oet + (k - 1); 6103 const PetscInt ovlb = oel + (k - 1); 6104 const PetscInt ovrb = ovlb + 1; 6105 const PetscInt ovrt = ovrb + 1; 6106 const PetscInt ovlt = ovrt + 1; 6107 PetscInt o; 6108 6109 /* bottom */ 6110 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6111 for (o = oeb; o < oer; ++o) 6112 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6113 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6114 /* middle */ 6115 for (i = 0; i < k - 1; ++i) { 6116 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6117 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6118 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6119 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6120 } 6121 /* top */ 6122 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6123 for (o = oel - 1; o >= oet; --o) 6124 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6125 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6126 foffset = offset; 6127 } else { 6128 PetscInt dof; 6129 6130 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6131 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6132 foffset = offset; 6133 } 6134 break; 6135 case 3: 6136 /* The original hex closure is 6137 6138 {c, 6139 f_b, f_t, f_f, f_b, f_r, f_l, 6140 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6141 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6142 */ 6143 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6144 if (!continuous && d < dim) continue; 6145 /* The SEM order is 6146 Bottom Slice 6147 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6148 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6149 v_blb, {e_bb}, v_brb, 6150 6151 Middle Slice (j) 6152 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6153 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6154 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6155 6156 Top Slice 6157 v_tlf, {e_tf}, v_trf, 6158 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6159 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6160 */ 6161 if (continuous) { 6162 const PetscInt oc = 0; 6163 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6164 const PetscInt oft = ofb + PetscSqr(k - 1); 6165 const PetscInt off = oft + PetscSqr(k - 1); 6166 const PetscInt ofk = off + PetscSqr(k - 1); 6167 const PetscInt ofr = ofk + PetscSqr(k - 1); 6168 const PetscInt ofl = ofr + PetscSqr(k - 1); 6169 const PetscInt oebl = ofl + PetscSqr(k - 1); 6170 const PetscInt oebb = oebl + (k - 1); 6171 const PetscInt oebr = oebb + (k - 1); 6172 const PetscInt oebf = oebr + (k - 1); 6173 const PetscInt oetf = oebf + (k - 1); 6174 const PetscInt oetr = oetf + (k - 1); 6175 const PetscInt oetb = oetr + (k - 1); 6176 const PetscInt oetl = oetb + (k - 1); 6177 const PetscInt oerf = oetl + (k - 1); 6178 const PetscInt oelf = oerf + (k - 1); 6179 const PetscInt oelb = oelf + (k - 1); 6180 const PetscInt oerb = oelb + (k - 1); 6181 const PetscInt ovblf = oerb + (k - 1); 6182 const PetscInt ovblb = ovblf + 1; 6183 const PetscInt ovbrb = ovblb + 1; 6184 const PetscInt ovbrf = ovbrb + 1; 6185 const PetscInt ovtlf = ovbrf + 1; 6186 const PetscInt ovtrf = ovtlf + 1; 6187 const PetscInt ovtrb = ovtrf + 1; 6188 const PetscInt ovtlb = ovtrb + 1; 6189 PetscInt o, n; 6190 6191 /* Bottom Slice */ 6192 /* bottom */ 6193 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6194 for (o = oetf - 1; o >= oebf; --o) 6195 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6196 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6197 /* middle */ 6198 for (i = 0; i < k - 1; ++i) { 6199 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6200 for (n = 0; n < k - 1; ++n) { 6201 o = ofb + n * (k - 1) + i; 6202 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6203 } 6204 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6205 } 6206 /* top */ 6207 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6208 for (o = oebb; o < oebr; ++o) 6209 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6210 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6211 6212 /* Middle Slice */ 6213 for (j = 0; j < k - 1; ++j) { 6214 /* bottom */ 6215 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6216 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6217 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6218 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6219 /* middle */ 6220 for (i = 0; i < k - 1; ++i) { 6221 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6222 for (n = 0; n < k - 1; ++n) 6223 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6224 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6225 } 6226 /* top */ 6227 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6228 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6229 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6230 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6231 } 6232 6233 /* Top Slice */ 6234 /* bottom */ 6235 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6236 for (o = oetf; o < oetr; ++o) 6237 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6238 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6239 /* middle */ 6240 for (i = 0; i < k - 1; ++i) { 6241 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6242 for (n = 0; n < k - 1; ++n) 6243 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6244 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6245 } 6246 /* top */ 6247 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6248 for (o = oetl - 1; o >= oetb; --o) 6249 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6250 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6251 6252 foffset = offset; 6253 } else { 6254 PetscInt dof; 6255 6256 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6257 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6258 foffset = offset; 6259 } 6260 break; 6261 default: 6262 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6263 } 6264 } 6265 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6266 /* Check permutation */ 6267 { 6268 PetscInt *check; 6269 6270 PetscCall(PetscMalloc1(size, &check)); 6271 for (i = 0; i < size; ++i) { 6272 check[i] = -1; 6273 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6274 } 6275 for (i = 0; i < size; ++i) check[perm[i]] = i; 6276 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6277 PetscCall(PetscFree(check)); 6278 } 6279 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6280 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6281 PetscInt *loc_perm; 6282 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6283 for (PetscInt i = 0; i < size; i++) { 6284 loc_perm[i] = perm[i]; 6285 loc_perm[size + i] = size + perm[i]; 6286 } 6287 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6288 } 6289 } 6290 PetscFunctionReturn(PETSC_SUCCESS); 6291 } 6292 6293 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6294 { 6295 PetscDS prob; 6296 PetscInt depth, Nf, h; 6297 DMLabel label; 6298 6299 PetscFunctionBeginHot; 6300 PetscCall(DMGetDS(dm, &prob)); 6301 Nf = prob->Nf; 6302 label = dm->depthLabel; 6303 *dspace = NULL; 6304 if (field < Nf) { 6305 PetscObject disc = prob->disc[field]; 6306 6307 if (disc->classid == PETSCFE_CLASSID) { 6308 PetscDualSpace dsp; 6309 6310 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6311 PetscCall(DMLabelGetNumValues(label, &depth)); 6312 PetscCall(DMLabelGetValue(label, point, &h)); 6313 h = depth - 1 - h; 6314 if (h) { 6315 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6316 } else { 6317 *dspace = dsp; 6318 } 6319 } 6320 } 6321 PetscFunctionReturn(PETSC_SUCCESS); 6322 } 6323 6324 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6325 { 6326 PetscScalar *array; 6327 const PetscScalar *vArray; 6328 const PetscInt *cone, *coneO; 6329 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6330 6331 PetscFunctionBeginHot; 6332 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6333 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6334 PetscCall(DMPlexGetCone(dm, point, &cone)); 6335 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6336 if (!values || !*values) { 6337 if ((point >= pStart) && (point < pEnd)) { 6338 PetscInt dof; 6339 6340 PetscCall(PetscSectionGetDof(section, point, &dof)); 6341 size += dof; 6342 } 6343 for (p = 0; p < numPoints; ++p) { 6344 const PetscInt cp = cone[p]; 6345 PetscInt dof; 6346 6347 if ((cp < pStart) || (cp >= pEnd)) continue; 6348 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6349 size += dof; 6350 } 6351 if (!values) { 6352 if (csize) *csize = size; 6353 PetscFunctionReturn(PETSC_SUCCESS); 6354 } 6355 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6356 } else { 6357 array = *values; 6358 } 6359 size = 0; 6360 PetscCall(VecGetArrayRead(v, &vArray)); 6361 if ((point >= pStart) && (point < pEnd)) { 6362 PetscInt dof, off, d; 6363 const PetscScalar *varr; 6364 6365 PetscCall(PetscSectionGetDof(section, point, &dof)); 6366 PetscCall(PetscSectionGetOffset(section, point, &off)); 6367 varr = PetscSafePointerPlusOffset(vArray, off); 6368 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6369 size += dof; 6370 } 6371 for (p = 0; p < numPoints; ++p) { 6372 const PetscInt cp = cone[p]; 6373 PetscInt o = coneO[p]; 6374 PetscInt dof, off, d; 6375 const PetscScalar *varr; 6376 6377 if ((cp < pStart) || (cp >= pEnd)) continue; 6378 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6379 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6380 varr = PetscSafePointerPlusOffset(vArray, off); 6381 if (o >= 0) { 6382 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6383 } else { 6384 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6385 } 6386 size += dof; 6387 } 6388 PetscCall(VecRestoreArrayRead(v, &vArray)); 6389 if (!*values) { 6390 if (csize) *csize = size; 6391 *values = array; 6392 } else { 6393 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6394 *csize = size; 6395 } 6396 PetscFunctionReturn(PETSC_SUCCESS); 6397 } 6398 6399 /* Compress out points not in the section */ 6400 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6401 { 6402 const PetscInt np = *numPoints; 6403 PetscInt pStart, pEnd, p, q; 6404 6405 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6406 for (p = 0, q = 0; p < np; ++p) { 6407 const PetscInt r = points[p * 2]; 6408 if ((r >= pStart) && (r < pEnd)) { 6409 points[q * 2] = r; 6410 points[q * 2 + 1] = points[p * 2 + 1]; 6411 ++q; 6412 } 6413 } 6414 *numPoints = q; 6415 return PETSC_SUCCESS; 6416 } 6417 6418 /* Compressed closure does not apply closure permutation */ 6419 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6420 { 6421 const PetscInt *cla = NULL; 6422 PetscInt np, *pts = NULL; 6423 6424 PetscFunctionBeginHot; 6425 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6426 if (!ornt && *clPoints) { 6427 PetscInt dof, off; 6428 6429 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6430 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6431 PetscCall(ISGetIndices(*clPoints, &cla)); 6432 np = dof / 2; 6433 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6434 } else { 6435 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6436 PetscCall(CompressPoints_Private(section, &np, pts)); 6437 } 6438 *numPoints = np; 6439 *points = pts; 6440 *clp = cla; 6441 PetscFunctionReturn(PETSC_SUCCESS); 6442 } 6443 6444 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6445 { 6446 PetscFunctionBeginHot; 6447 if (!*clPoints) { 6448 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6449 } else { 6450 PetscCall(ISRestoreIndices(*clPoints, clp)); 6451 } 6452 *numPoints = 0; 6453 *points = NULL; 6454 *clSec = NULL; 6455 *clPoints = NULL; 6456 *clp = NULL; 6457 PetscFunctionReturn(PETSC_SUCCESS); 6458 } 6459 6460 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6461 { 6462 PetscInt offset = 0, p; 6463 const PetscInt **perms = NULL; 6464 const PetscScalar **flips = NULL; 6465 6466 PetscFunctionBeginHot; 6467 *size = 0; 6468 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6469 for (p = 0; p < numPoints; p++) { 6470 const PetscInt point = points[2 * p]; 6471 const PetscInt *perm = perms ? perms[p] : NULL; 6472 const PetscScalar *flip = flips ? flips[p] : NULL; 6473 PetscInt dof, off, d; 6474 const PetscScalar *varr; 6475 6476 PetscCall(PetscSectionGetDof(section, point, &dof)); 6477 PetscCall(PetscSectionGetOffset(section, point, &off)); 6478 varr = PetscSafePointerPlusOffset(vArray, off); 6479 if (clperm) { 6480 if (perm) { 6481 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6482 } else { 6483 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6484 } 6485 if (flip) { 6486 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6487 } 6488 } else { 6489 if (perm) { 6490 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6491 } else { 6492 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6493 } 6494 if (flip) { 6495 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6496 } 6497 } 6498 offset += dof; 6499 } 6500 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6501 *size = offset; 6502 PetscFunctionReturn(PETSC_SUCCESS); 6503 } 6504 6505 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[]) 6506 { 6507 PetscInt offset = 0, f; 6508 6509 PetscFunctionBeginHot; 6510 *size = 0; 6511 for (f = 0; f < numFields; ++f) { 6512 PetscInt p; 6513 const PetscInt **perms = NULL; 6514 const PetscScalar **flips = NULL; 6515 6516 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6517 for (p = 0; p < numPoints; p++) { 6518 const PetscInt point = points[2 * p]; 6519 PetscInt fdof, foff, b; 6520 const PetscScalar *varr; 6521 const PetscInt *perm = perms ? perms[p] : NULL; 6522 const PetscScalar *flip = flips ? flips[p] : NULL; 6523 6524 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6525 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6526 varr = &vArray[foff]; 6527 if (clperm) { 6528 if (perm) { 6529 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6530 } else { 6531 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6532 } 6533 if (flip) { 6534 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6535 } 6536 } else { 6537 if (perm) { 6538 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6539 } else { 6540 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6541 } 6542 if (flip) { 6543 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6544 } 6545 } 6546 offset += fdof; 6547 } 6548 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6549 } 6550 *size = offset; 6551 PetscFunctionReturn(PETSC_SUCCESS); 6552 } 6553 6554 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6555 { 6556 PetscSection clSection; 6557 IS clPoints; 6558 PetscInt *points = NULL; 6559 const PetscInt *clp, *perm = NULL; 6560 PetscInt depth, numFields, numPoints, asize; 6561 6562 PetscFunctionBeginHot; 6563 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6564 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6565 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6566 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6567 PetscCall(DMPlexGetDepth(dm, &depth)); 6568 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6569 if (depth == 1 && numFields < 2) { 6570 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6571 PetscFunctionReturn(PETSC_SUCCESS); 6572 } 6573 /* Get points */ 6574 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6575 /* Get sizes */ 6576 asize = 0; 6577 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6578 PetscInt dof; 6579 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6580 asize += dof; 6581 } 6582 if (values) { 6583 const PetscScalar *vArray; 6584 PetscInt size; 6585 6586 if (*values) { 6587 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); 6588 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6589 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6590 PetscCall(VecGetArrayRead(v, &vArray)); 6591 /* Get values */ 6592 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6593 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6594 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6595 /* Cleanup array */ 6596 PetscCall(VecRestoreArrayRead(v, &vArray)); 6597 } 6598 if (csize) *csize = asize; 6599 /* Cleanup points */ 6600 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6601 PetscFunctionReturn(PETSC_SUCCESS); 6602 } 6603 6604 /*@C 6605 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6606 6607 Not collective 6608 6609 Input Parameters: 6610 + dm - The `DM` 6611 . section - The section describing the layout in `v`, or `NULL` to use the default section 6612 . v - The local vector 6613 - point - The point in the `DM` 6614 6615 Input/Output Parameters: 6616 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6617 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6618 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6619 6620 Level: intermediate 6621 6622 Notes: 6623 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6624 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6625 assembly function, and a user may already have allocated storage for this operation. 6626 6627 A typical use could be 6628 .vb 6629 values = NULL; 6630 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6631 for (cl = 0; cl < clSize; ++cl) { 6632 <Compute on closure> 6633 } 6634 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6635 .ve 6636 or 6637 .vb 6638 PetscMalloc1(clMaxSize, &values); 6639 for (p = pStart; p < pEnd; ++p) { 6640 clSize = clMaxSize; 6641 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6642 for (cl = 0; cl < clSize; ++cl) { 6643 <Compute on closure> 6644 } 6645 } 6646 PetscFree(values); 6647 .ve 6648 6649 Fortran Notes: 6650 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6651 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6652 6653 `values` must be declared with 6654 .vb 6655 PetscScalar,dimension(:),pointer :: values 6656 .ve 6657 and it will be allocated internally by PETSc to hold the values returned 6658 6659 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6660 @*/ 6661 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6662 { 6663 PetscFunctionBeginHot; 6664 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6665 PetscFunctionReturn(PETSC_SUCCESS); 6666 } 6667 6668 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6669 { 6670 DMLabel depthLabel; 6671 PetscSection clSection; 6672 IS clPoints; 6673 PetscScalar *array; 6674 const PetscScalar *vArray; 6675 PetscInt *points = NULL; 6676 const PetscInt *clp, *perm = NULL; 6677 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6678 6679 PetscFunctionBeginHot; 6680 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6681 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6682 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6683 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6684 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6685 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6686 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6687 if (mdepth == 1 && numFields < 2) { 6688 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6689 PetscFunctionReturn(PETSC_SUCCESS); 6690 } 6691 /* Get points */ 6692 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6693 for (clsize = 0, p = 0; p < Np; p++) { 6694 PetscInt dof; 6695 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6696 clsize += dof; 6697 } 6698 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6699 /* Filter points */ 6700 for (p = 0; p < numPoints * 2; p += 2) { 6701 PetscInt dep; 6702 6703 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6704 if (dep != depth) continue; 6705 points[Np * 2 + 0] = points[p]; 6706 points[Np * 2 + 1] = points[p + 1]; 6707 ++Np; 6708 } 6709 /* Get array */ 6710 if (!values || !*values) { 6711 PetscInt asize = 0, dof; 6712 6713 for (p = 0; p < Np * 2; p += 2) { 6714 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6715 asize += dof; 6716 } 6717 if (!values) { 6718 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6719 if (csize) *csize = asize; 6720 PetscFunctionReturn(PETSC_SUCCESS); 6721 } 6722 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6723 } else { 6724 array = *values; 6725 } 6726 PetscCall(VecGetArrayRead(v, &vArray)); 6727 /* Get values */ 6728 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6729 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6730 /* Cleanup points */ 6731 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6732 /* Cleanup array */ 6733 PetscCall(VecRestoreArrayRead(v, &vArray)); 6734 if (!*values) { 6735 if (csize) *csize = size; 6736 *values = array; 6737 } else { 6738 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6739 *csize = size; 6740 } 6741 PetscFunctionReturn(PETSC_SUCCESS); 6742 } 6743 6744 /*@C 6745 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6746 6747 Not collective 6748 6749 Input Parameters: 6750 + dm - The `DM` 6751 . section - The section describing the layout in `v`, or `NULL` to use the default section 6752 . v - The local vector 6753 . point - The point in the `DM` 6754 . csize - The number of values in the closure, or `NULL` 6755 - values - The array of values 6756 6757 Level: intermediate 6758 6759 Note: 6760 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6761 6762 Fortran Note: 6763 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6764 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6765 6766 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6767 @*/ 6768 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6769 { 6770 PetscInt size = 0; 6771 6772 PetscFunctionBegin; 6773 /* Should work without recalculating size */ 6774 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6775 *values = NULL; 6776 PetscFunctionReturn(PETSC_SUCCESS); 6777 } 6778 6779 static inline void add(PetscScalar *x, PetscScalar y) 6780 { 6781 *x += y; 6782 } 6783 static inline void insert(PetscScalar *x, PetscScalar y) 6784 { 6785 *x = y; 6786 } 6787 6788 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[]) 6789 { 6790 PetscInt cdof; /* The number of constraints on this point */ 6791 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6792 PetscScalar *a; 6793 PetscInt off, cind = 0, k; 6794 6795 PetscFunctionBegin; 6796 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6797 PetscCall(PetscSectionGetOffset(section, point, &off)); 6798 a = &array[off]; 6799 if (!cdof || setBC) { 6800 if (clperm) { 6801 if (perm) { 6802 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6803 } else { 6804 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6805 } 6806 } else { 6807 if (perm) { 6808 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6809 } else { 6810 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6811 } 6812 } 6813 } else { 6814 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6815 if (clperm) { 6816 if (perm) { 6817 for (k = 0; k < dof; ++k) { 6818 if ((cind < cdof) && (k == cdofs[cind])) { 6819 ++cind; 6820 continue; 6821 } 6822 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6823 } 6824 } else { 6825 for (k = 0; k < dof; ++k) { 6826 if ((cind < cdof) && (k == cdofs[cind])) { 6827 ++cind; 6828 continue; 6829 } 6830 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6831 } 6832 } 6833 } else { 6834 if (perm) { 6835 for (k = 0; k < dof; ++k) { 6836 if ((cind < cdof) && (k == cdofs[cind])) { 6837 ++cind; 6838 continue; 6839 } 6840 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6841 } 6842 } else { 6843 for (k = 0; k < dof; ++k) { 6844 if ((cind < cdof) && (k == cdofs[cind])) { 6845 ++cind; 6846 continue; 6847 } 6848 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6849 } 6850 } 6851 } 6852 } 6853 PetscFunctionReturn(PETSC_SUCCESS); 6854 } 6855 6856 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[]) 6857 { 6858 PetscInt cdof; /* The number of constraints on this point */ 6859 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6860 PetscScalar *a; 6861 PetscInt off, cind = 0, k; 6862 6863 PetscFunctionBegin; 6864 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6865 PetscCall(PetscSectionGetOffset(section, point, &off)); 6866 a = &array[off]; 6867 if (cdof) { 6868 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6869 if (clperm) { 6870 if (perm) { 6871 for (k = 0; k < dof; ++k) { 6872 if ((cind < cdof) && (k == cdofs[cind])) { 6873 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6874 cind++; 6875 } 6876 } 6877 } else { 6878 for (k = 0; k < dof; ++k) { 6879 if ((cind < cdof) && (k == cdofs[cind])) { 6880 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6881 cind++; 6882 } 6883 } 6884 } 6885 } else { 6886 if (perm) { 6887 for (k = 0; k < dof; ++k) { 6888 if ((cind < cdof) && (k == cdofs[cind])) { 6889 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6890 cind++; 6891 } 6892 } 6893 } else { 6894 for (k = 0; k < dof; ++k) { 6895 if ((cind < cdof) && (k == cdofs[cind])) { 6896 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6897 cind++; 6898 } 6899 } 6900 } 6901 } 6902 } 6903 PetscFunctionReturn(PETSC_SUCCESS); 6904 } 6905 6906 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[]) 6907 { 6908 PetscScalar *a; 6909 PetscInt fdof, foff, fcdof, foffset = *offset; 6910 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6911 PetscInt cind = 0, b; 6912 6913 PetscFunctionBegin; 6914 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6915 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6916 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6917 a = &array[foff]; 6918 if (!fcdof || setBC) { 6919 if (clperm) { 6920 if (perm) { 6921 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6922 } else { 6923 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6924 } 6925 } else { 6926 if (perm) { 6927 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6928 } else { 6929 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6930 } 6931 } 6932 } else { 6933 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6934 if (clperm) { 6935 if (perm) { 6936 for (b = 0; b < fdof; b++) { 6937 if ((cind < fcdof) && (b == fcdofs[cind])) { 6938 ++cind; 6939 continue; 6940 } 6941 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6942 } 6943 } else { 6944 for (b = 0; b < fdof; b++) { 6945 if ((cind < fcdof) && (b == fcdofs[cind])) { 6946 ++cind; 6947 continue; 6948 } 6949 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6950 } 6951 } 6952 } else { 6953 if (perm) { 6954 for (b = 0; b < fdof; b++) { 6955 if ((cind < fcdof) && (b == fcdofs[cind])) { 6956 ++cind; 6957 continue; 6958 } 6959 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6960 } 6961 } else { 6962 for (b = 0; b < fdof; b++) { 6963 if ((cind < fcdof) && (b == fcdofs[cind])) { 6964 ++cind; 6965 continue; 6966 } 6967 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6968 } 6969 } 6970 } 6971 } 6972 *offset += fdof; 6973 PetscFunctionReturn(PETSC_SUCCESS); 6974 } 6975 6976 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[]) 6977 { 6978 PetscScalar *a; 6979 PetscInt fdof, foff, fcdof, foffset = *offset; 6980 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6981 PetscInt Nc, cind = 0, ncind = 0, b; 6982 PetscBool ncSet, fcSet; 6983 6984 PetscFunctionBegin; 6985 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6986 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6987 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6988 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6989 a = &array[foff]; 6990 if (fcdof) { 6991 /* We just override fcdof and fcdofs with Ncc and comps */ 6992 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6993 if (clperm) { 6994 if (perm) { 6995 if (comps) { 6996 for (b = 0; b < fdof; b++) { 6997 ncSet = fcSet = PETSC_FALSE; 6998 if (b % Nc == comps[ncind]) { 6999 ncind = (ncind + 1) % Ncc; 7000 ncSet = PETSC_TRUE; 7001 } 7002 if ((cind < fcdof) && (b == fcdofs[cind])) { 7003 ++cind; 7004 fcSet = PETSC_TRUE; 7005 } 7006 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7007 } 7008 } else { 7009 for (b = 0; b < fdof; b++) { 7010 if ((cind < fcdof) && (b == fcdofs[cind])) { 7011 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7012 ++cind; 7013 } 7014 } 7015 } 7016 } else { 7017 if (comps) { 7018 for (b = 0; b < fdof; b++) { 7019 ncSet = fcSet = PETSC_FALSE; 7020 if (b % Nc == comps[ncind]) { 7021 ncind = (ncind + 1) % Ncc; 7022 ncSet = PETSC_TRUE; 7023 } 7024 if ((cind < fcdof) && (b == fcdofs[cind])) { 7025 ++cind; 7026 fcSet = PETSC_TRUE; 7027 } 7028 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7029 } 7030 } else { 7031 for (b = 0; b < fdof; b++) { 7032 if ((cind < fcdof) && (b == fcdofs[cind])) { 7033 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7034 ++cind; 7035 } 7036 } 7037 } 7038 } 7039 } else { 7040 if (perm) { 7041 if (comps) { 7042 for (b = 0; b < fdof; b++) { 7043 ncSet = fcSet = PETSC_FALSE; 7044 if (b % Nc == comps[ncind]) { 7045 ncind = (ncind + 1) % Ncc; 7046 ncSet = PETSC_TRUE; 7047 } 7048 if ((cind < fcdof) && (b == fcdofs[cind])) { 7049 ++cind; 7050 fcSet = PETSC_TRUE; 7051 } 7052 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7053 } 7054 } else { 7055 for (b = 0; b < fdof; b++) { 7056 if ((cind < fcdof) && (b == fcdofs[cind])) { 7057 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7058 ++cind; 7059 } 7060 } 7061 } 7062 } else { 7063 if (comps) { 7064 for (b = 0; b < fdof; b++) { 7065 ncSet = fcSet = PETSC_FALSE; 7066 if (b % Nc == comps[ncind]) { 7067 ncind = (ncind + 1) % Ncc; 7068 ncSet = PETSC_TRUE; 7069 } 7070 if ((cind < fcdof) && (b == fcdofs[cind])) { 7071 ++cind; 7072 fcSet = PETSC_TRUE; 7073 } 7074 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7075 } 7076 } else { 7077 for (b = 0; b < fdof; b++) { 7078 if ((cind < fcdof) && (b == fcdofs[cind])) { 7079 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7080 ++cind; 7081 } 7082 } 7083 } 7084 } 7085 } 7086 } 7087 *offset += fdof; 7088 PetscFunctionReturn(PETSC_SUCCESS); 7089 } 7090 7091 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7092 { 7093 PetscScalar *array; 7094 const PetscInt *cone, *coneO; 7095 PetscInt pStart, pEnd, p, numPoints, off, dof; 7096 7097 PetscFunctionBeginHot; 7098 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7099 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7100 PetscCall(DMPlexGetCone(dm, point, &cone)); 7101 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7102 PetscCall(VecGetArray(v, &array)); 7103 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7104 const PetscInt cp = !p ? point : cone[p - 1]; 7105 const PetscInt o = !p ? 0 : coneO[p - 1]; 7106 7107 if ((cp < pStart) || (cp >= pEnd)) { 7108 dof = 0; 7109 continue; 7110 } 7111 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7112 /* ADD_VALUES */ 7113 { 7114 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7115 PetscScalar *a; 7116 PetscInt cdof, coff, cind = 0, k; 7117 7118 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7119 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7120 a = &array[coff]; 7121 if (!cdof) { 7122 if (o >= 0) { 7123 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7124 } else { 7125 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7126 } 7127 } else { 7128 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7129 if (o >= 0) { 7130 for (k = 0; k < dof; ++k) { 7131 if ((cind < cdof) && (k == cdofs[cind])) { 7132 ++cind; 7133 continue; 7134 } 7135 a[k] += values[off + k]; 7136 } 7137 } else { 7138 for (k = 0; k < dof; ++k) { 7139 if ((cind < cdof) && (k == cdofs[cind])) { 7140 ++cind; 7141 continue; 7142 } 7143 a[k] += values[off + dof - k - 1]; 7144 } 7145 } 7146 } 7147 } 7148 } 7149 PetscCall(VecRestoreArray(v, &array)); 7150 PetscFunctionReturn(PETSC_SUCCESS); 7151 } 7152 7153 /*@C 7154 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7155 7156 Not collective 7157 7158 Input Parameters: 7159 + dm - The `DM` 7160 . section - The section describing the layout in `v`, or `NULL` to use the default section 7161 . v - The local vector 7162 . point - The point in the `DM` 7163 . values - The array of values 7164 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7165 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7166 7167 Level: intermediate 7168 7169 Note: 7170 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7171 7172 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7173 @*/ 7174 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7175 { 7176 PetscSection clSection; 7177 IS clPoints; 7178 PetscScalar *array; 7179 PetscInt *points = NULL; 7180 const PetscInt *clp, *clperm = NULL; 7181 PetscInt depth, numFields, numPoints, p, clsize; 7182 7183 PetscFunctionBeginHot; 7184 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7185 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7186 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7187 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7188 PetscCall(DMPlexGetDepth(dm, &depth)); 7189 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7190 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7191 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7192 PetscFunctionReturn(PETSC_SUCCESS); 7193 } 7194 /* Get points */ 7195 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7196 for (clsize = 0, p = 0; p < numPoints; p++) { 7197 PetscInt dof; 7198 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7199 clsize += dof; 7200 } 7201 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7202 /* Get array */ 7203 PetscCall(VecGetArray(v, &array)); 7204 /* Get values */ 7205 if (numFields > 0) { 7206 PetscInt offset = 0, f; 7207 for (f = 0; f < numFields; ++f) { 7208 const PetscInt **perms = NULL; 7209 const PetscScalar **flips = NULL; 7210 7211 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7212 switch (mode) { 7213 case INSERT_VALUES: 7214 for (p = 0; p < numPoints; p++) { 7215 const PetscInt point = points[2 * p]; 7216 const PetscInt *perm = perms ? perms[p] : NULL; 7217 const PetscScalar *flip = flips ? flips[p] : NULL; 7218 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7219 } 7220 break; 7221 case INSERT_ALL_VALUES: 7222 for (p = 0; p < numPoints; p++) { 7223 const PetscInt point = points[2 * p]; 7224 const PetscInt *perm = perms ? perms[p] : NULL; 7225 const PetscScalar *flip = flips ? flips[p] : NULL; 7226 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7227 } 7228 break; 7229 case INSERT_BC_VALUES: 7230 for (p = 0; p < numPoints; p++) { 7231 const PetscInt point = points[2 * p]; 7232 const PetscInt *perm = perms ? perms[p] : NULL; 7233 const PetscScalar *flip = flips ? flips[p] : NULL; 7234 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7235 } 7236 break; 7237 case ADD_VALUES: 7238 for (p = 0; p < numPoints; p++) { 7239 const PetscInt point = points[2 * p]; 7240 const PetscInt *perm = perms ? perms[p] : NULL; 7241 const PetscScalar *flip = flips ? flips[p] : NULL; 7242 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7243 } 7244 break; 7245 case ADD_ALL_VALUES: 7246 for (p = 0; p < numPoints; p++) { 7247 const PetscInt point = points[2 * p]; 7248 const PetscInt *perm = perms ? perms[p] : NULL; 7249 const PetscScalar *flip = flips ? flips[p] : NULL; 7250 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7251 } 7252 break; 7253 case ADD_BC_VALUES: 7254 for (p = 0; p < numPoints; p++) { 7255 const PetscInt point = points[2 * p]; 7256 const PetscInt *perm = perms ? perms[p] : NULL; 7257 const PetscScalar *flip = flips ? flips[p] : NULL; 7258 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7259 } 7260 break; 7261 default: 7262 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7263 } 7264 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7265 } 7266 } else { 7267 PetscInt dof, off; 7268 const PetscInt **perms = NULL; 7269 const PetscScalar **flips = NULL; 7270 7271 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7272 switch (mode) { 7273 case INSERT_VALUES: 7274 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7275 const PetscInt point = points[2 * p]; 7276 const PetscInt *perm = perms ? perms[p] : NULL; 7277 const PetscScalar *flip = flips ? flips[p] : NULL; 7278 PetscCall(PetscSectionGetDof(section, point, &dof)); 7279 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7280 } 7281 break; 7282 case INSERT_ALL_VALUES: 7283 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7284 const PetscInt point = points[2 * p]; 7285 const PetscInt *perm = perms ? perms[p] : NULL; 7286 const PetscScalar *flip = flips ? flips[p] : NULL; 7287 PetscCall(PetscSectionGetDof(section, point, &dof)); 7288 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7289 } 7290 break; 7291 case INSERT_BC_VALUES: 7292 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7293 const PetscInt point = points[2 * p]; 7294 const PetscInt *perm = perms ? perms[p] : NULL; 7295 const PetscScalar *flip = flips ? flips[p] : NULL; 7296 PetscCall(PetscSectionGetDof(section, point, &dof)); 7297 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7298 } 7299 break; 7300 case ADD_VALUES: 7301 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7302 const PetscInt point = points[2 * p]; 7303 const PetscInt *perm = perms ? perms[p] : NULL; 7304 const PetscScalar *flip = flips ? flips[p] : NULL; 7305 PetscCall(PetscSectionGetDof(section, point, &dof)); 7306 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7307 } 7308 break; 7309 case ADD_ALL_VALUES: 7310 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7311 const PetscInt point = points[2 * p]; 7312 const PetscInt *perm = perms ? perms[p] : NULL; 7313 const PetscScalar *flip = flips ? flips[p] : NULL; 7314 PetscCall(PetscSectionGetDof(section, point, &dof)); 7315 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7316 } 7317 break; 7318 case ADD_BC_VALUES: 7319 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7320 const PetscInt point = points[2 * p]; 7321 const PetscInt *perm = perms ? perms[p] : NULL; 7322 const PetscScalar *flip = flips ? flips[p] : NULL; 7323 PetscCall(PetscSectionGetDof(section, point, &dof)); 7324 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7325 } 7326 break; 7327 default: 7328 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7329 } 7330 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7331 } 7332 /* Cleanup points */ 7333 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7334 /* Cleanup array */ 7335 PetscCall(VecRestoreArray(v, &array)); 7336 PetscFunctionReturn(PETSC_SUCCESS); 7337 } 7338 7339 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7340 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7341 { 7342 PetscFunctionBegin; 7343 *contains = PETSC_TRUE; 7344 if (label) { 7345 PetscInt fdof; 7346 7347 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7348 if (!*contains) { 7349 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7350 *offset += fdof; 7351 PetscFunctionReturn(PETSC_SUCCESS); 7352 } 7353 } 7354 PetscFunctionReturn(PETSC_SUCCESS); 7355 } 7356 7357 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7358 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) 7359 { 7360 PetscSection clSection; 7361 IS clPoints; 7362 PetscScalar *array; 7363 PetscInt *points = NULL; 7364 const PetscInt *clp; 7365 PetscInt numFields, numPoints, p; 7366 PetscInt offset = 0, f; 7367 7368 PetscFunctionBeginHot; 7369 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7370 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7371 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7372 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7373 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7374 /* Get points */ 7375 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7376 /* Get array */ 7377 PetscCall(VecGetArray(v, &array)); 7378 /* Get values */ 7379 for (f = 0; f < numFields; ++f) { 7380 const PetscInt **perms = NULL; 7381 const PetscScalar **flips = NULL; 7382 PetscBool contains; 7383 7384 if (!fieldActive[f]) { 7385 for (p = 0; p < numPoints * 2; p += 2) { 7386 PetscInt fdof; 7387 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7388 offset += fdof; 7389 } 7390 continue; 7391 } 7392 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7393 switch (mode) { 7394 case INSERT_VALUES: 7395 for (p = 0; p < numPoints; p++) { 7396 const PetscInt point = points[2 * p]; 7397 const PetscInt *perm = perms ? perms[p] : NULL; 7398 const PetscScalar *flip = flips ? flips[p] : NULL; 7399 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7400 if (!contains) continue; 7401 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7402 } 7403 break; 7404 case INSERT_ALL_VALUES: 7405 for (p = 0; p < numPoints; p++) { 7406 const PetscInt point = points[2 * p]; 7407 const PetscInt *perm = perms ? perms[p] : NULL; 7408 const PetscScalar *flip = flips ? flips[p] : NULL; 7409 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7410 if (!contains) continue; 7411 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7412 } 7413 break; 7414 case INSERT_BC_VALUES: 7415 for (p = 0; p < numPoints; p++) { 7416 const PetscInt point = points[2 * p]; 7417 const PetscInt *perm = perms ? perms[p] : NULL; 7418 const PetscScalar *flip = flips ? flips[p] : NULL; 7419 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7420 if (!contains) continue; 7421 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7422 } 7423 break; 7424 case ADD_VALUES: 7425 for (p = 0; p < numPoints; p++) { 7426 const PetscInt point = points[2 * p]; 7427 const PetscInt *perm = perms ? perms[p] : NULL; 7428 const PetscScalar *flip = flips ? flips[p] : NULL; 7429 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7430 if (!contains) continue; 7431 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7432 } 7433 break; 7434 case ADD_ALL_VALUES: 7435 for (p = 0; p < numPoints; p++) { 7436 const PetscInt point = points[2 * p]; 7437 const PetscInt *perm = perms ? perms[p] : NULL; 7438 const PetscScalar *flip = flips ? flips[p] : NULL; 7439 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7440 if (!contains) continue; 7441 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7442 } 7443 break; 7444 default: 7445 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7446 } 7447 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7448 } 7449 /* Cleanup points */ 7450 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7451 /* Cleanup array */ 7452 PetscCall(VecRestoreArray(v, &array)); 7453 PetscFunctionReturn(PETSC_SUCCESS); 7454 } 7455 7456 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7457 { 7458 PetscMPIInt rank; 7459 PetscInt i, j; 7460 7461 PetscFunctionBegin; 7462 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7463 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7464 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7465 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7466 numCIndices = numCIndices ? numCIndices : numRIndices; 7467 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7468 for (i = 0; i < numRIndices; i++) { 7469 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7470 for (j = 0; j < numCIndices; j++) { 7471 #if defined(PETSC_USE_COMPLEX) 7472 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7473 #else 7474 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7475 #endif 7476 } 7477 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7478 } 7479 PetscFunctionReturn(PETSC_SUCCESS); 7480 } 7481 7482 /* 7483 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7484 7485 Input Parameters: 7486 + section - The section for this data layout 7487 . islocal - Is the section (and thus indices being requested) local or global? 7488 . point - The point contributing dofs with these indices 7489 . off - The global offset of this point 7490 . loff - The local offset of each field 7491 . setBC - The flag determining whether to include indices of boundary values 7492 . perm - A permutation of the dofs on this point, or NULL 7493 - indperm - A permutation of the entire indices array, or NULL 7494 7495 Output Parameter: 7496 . indices - Indices for dofs on this point 7497 7498 Level: developer 7499 7500 Note: The indices could be local or global, depending on the value of 'off'. 7501 */ 7502 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7503 { 7504 PetscInt dof; /* The number of unknowns on this point */ 7505 PetscInt cdof; /* The number of constraints on this point */ 7506 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7507 PetscInt cind = 0, k; 7508 7509 PetscFunctionBegin; 7510 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7511 PetscCall(PetscSectionGetDof(section, point, &dof)); 7512 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7513 if (!cdof || setBC) { 7514 for (k = 0; k < dof; ++k) { 7515 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7516 const PetscInt ind = indperm ? indperm[preind] : preind; 7517 7518 indices[ind] = off + k; 7519 } 7520 } else { 7521 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7522 for (k = 0; k < dof; ++k) { 7523 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7524 const PetscInt ind = indperm ? indperm[preind] : preind; 7525 7526 if ((cind < cdof) && (k == cdofs[cind])) { 7527 /* Insert check for returning constrained indices */ 7528 indices[ind] = -(off + k + 1); 7529 ++cind; 7530 } else { 7531 indices[ind] = off + k - (islocal ? 0 : cind); 7532 } 7533 } 7534 } 7535 *loff += dof; 7536 PetscFunctionReturn(PETSC_SUCCESS); 7537 } 7538 7539 /* 7540 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7541 7542 Input Parameters: 7543 + section - a section (global or local) 7544 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7545 . point - point within section 7546 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7547 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7548 . setBC - identify constrained (boundary condition) points via involution. 7549 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7550 . permsoff - offset 7551 - indperm - index permutation 7552 7553 Output Parameter: 7554 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7555 . indices - array to hold indices (as defined by section) of each dof associated with point 7556 7557 Notes: 7558 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7559 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7560 in the local vector. 7561 7562 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7563 significant). It is invalid to call with a global section and setBC=true. 7564 7565 Developer Note: 7566 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7567 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7568 offset could be obtained from the section instead of passing it explicitly as we do now. 7569 7570 Example: 7571 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7572 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7573 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7574 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. 7575 7576 Level: developer 7577 */ 7578 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[]) 7579 { 7580 PetscInt numFields, foff, f; 7581 7582 PetscFunctionBegin; 7583 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7584 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7585 for (f = 0, foff = 0; f < numFields; ++f) { 7586 PetscInt fdof, cfdof; 7587 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7588 PetscInt cind = 0, b; 7589 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7590 7591 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7592 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7593 if (!cfdof || setBC) { 7594 for (b = 0; b < fdof; ++b) { 7595 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7596 const PetscInt ind = indperm ? indperm[preind] : preind; 7597 7598 indices[ind] = off + foff + b; 7599 } 7600 } else { 7601 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7602 for (b = 0; b < fdof; ++b) { 7603 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7604 const PetscInt ind = indperm ? indperm[preind] : preind; 7605 7606 if ((cind < cfdof) && (b == fcdofs[cind])) { 7607 indices[ind] = -(off + foff + b + 1); 7608 ++cind; 7609 } else { 7610 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7611 } 7612 } 7613 } 7614 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7615 foffs[f] += fdof; 7616 } 7617 PetscFunctionReturn(PETSC_SUCCESS); 7618 } 7619 7620 /* 7621 This version believes the globalSection offsets for each field, rather than just the point offset 7622 7623 . foffs - The offset into 'indices' for each field, since it is segregated by field 7624 7625 Notes: 7626 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7627 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7628 */ 7629 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7630 { 7631 PetscInt numFields, foff, f; 7632 7633 PetscFunctionBegin; 7634 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7635 for (f = 0; f < numFields; ++f) { 7636 PetscInt fdof, cfdof; 7637 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7638 PetscInt cind = 0, b; 7639 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7640 7641 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7642 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7643 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7644 if (!cfdof) { 7645 for (b = 0; b < fdof; ++b) { 7646 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7647 const PetscInt ind = indperm ? indperm[preind] : preind; 7648 7649 indices[ind] = foff + b; 7650 } 7651 } else { 7652 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7653 for (b = 0; b < fdof; ++b) { 7654 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7655 const PetscInt ind = indperm ? indperm[preind] : preind; 7656 7657 if ((cind < cfdof) && (b == fcdofs[cind])) { 7658 indices[ind] = -(foff + b + 1); 7659 ++cind; 7660 } else { 7661 indices[ind] = foff + b - cind; 7662 } 7663 } 7664 } 7665 foffs[f] += fdof; 7666 } 7667 PetscFunctionReturn(PETSC_SUCCESS); 7668 } 7669 7670 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7671 { 7672 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7673 7674 PetscFunctionBegin; 7675 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7676 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7677 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7678 for (PetscInt p = 0; p < nPoints; p++) { 7679 PetscInt b = pnts[2 * p]; 7680 PetscInt bSecDof = 0, bOff; 7681 PetscInt cSecDof = 0; 7682 PetscSection indices_section; 7683 7684 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7685 if (!bSecDof) continue; 7686 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7687 indices_section = cSecDof > 0 ? cSec : section; 7688 if (numFields) { 7689 PetscInt fStart[32], fEnd[32]; 7690 7691 fStart[0] = 0; 7692 fEnd[0] = 0; 7693 for (PetscInt f = 0; f < numFields; f++) { 7694 PetscInt fDof = 0; 7695 7696 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7697 fStart[f + 1] = fStart[f] + fDof; 7698 fEnd[f + 1] = fStart[f + 1]; 7699 } 7700 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7701 // only apply permutations on one side 7702 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7703 for (PetscInt f = 0; f < numFields; f++) { 7704 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7705 } 7706 } else { 7707 PetscInt bEnd = 0; 7708 7709 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7710 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7711 7712 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7713 } 7714 } 7715 PetscFunctionReturn(PETSC_SUCCESS); 7716 } 7717 7718 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[]) 7719 { 7720 Mat cMat; 7721 PetscSection aSec, cSec; 7722 IS aIS; 7723 PetscInt aStart = -1, aEnd = -1; 7724 PetscInt sStart = -1, sEnd = -1; 7725 PetscInt cStart = -1, cEnd = -1; 7726 const PetscInt *anchors; 7727 PetscInt numFields, p; 7728 PetscInt newNumPoints = 0, newNumIndices = 0; 7729 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7730 PetscInt oldOffsets[32]; 7731 PetscInt newOffsets[32]; 7732 PetscInt oldOffsetsCopy[32]; 7733 PetscInt newOffsetsCopy[32]; 7734 PetscScalar *modMat = NULL; 7735 PetscBool anyConstrained = PETSC_FALSE; 7736 7737 PetscFunctionBegin; 7738 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7739 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7740 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7741 7742 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7743 /* if there are point-to-point constraints */ 7744 if (aSec) { 7745 PetscCall(PetscArrayzero(newOffsets, 32)); 7746 PetscCall(PetscArrayzero(oldOffsets, 32)); 7747 PetscCall(ISGetIndices(aIS, &anchors)); 7748 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7749 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7750 /* figure out how many points are going to be in the new element matrix 7751 * (we allow double counting, because it's all just going to be summed 7752 * into the global matrix anyway) */ 7753 for (p = 0; p < 2 * numPoints; p += 2) { 7754 PetscInt b = points[p]; 7755 PetscInt bDof = 0, bSecDof = 0; 7756 7757 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7758 if (!bSecDof) continue; 7759 7760 for (PetscInt f = 0; f < numFields; f++) { 7761 PetscInt fDof = 0; 7762 7763 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7764 oldOffsets[f + 1] += fDof; 7765 } 7766 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7767 if (bDof) { 7768 /* this point is constrained */ 7769 /* it is going to be replaced by its anchors */ 7770 PetscInt bOff, q; 7771 7772 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7773 for (q = 0; q < bDof; q++) { 7774 PetscInt a = anchors[bOff + q]; 7775 PetscInt aDof = 0; 7776 7777 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7778 if (aDof) { 7779 anyConstrained = PETSC_TRUE; 7780 newNumPoints += 1; 7781 } 7782 newNumIndices += aDof; 7783 for (PetscInt f = 0; f < numFields; ++f) { 7784 PetscInt fDof = 0; 7785 7786 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7787 newOffsets[f + 1] += fDof; 7788 } 7789 } 7790 } else { 7791 /* this point is not constrained */ 7792 newNumPoints++; 7793 newNumIndices += bSecDof; 7794 for (PetscInt f = 0; f < numFields; ++f) { 7795 PetscInt fDof; 7796 7797 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7798 newOffsets[f + 1] += fDof; 7799 } 7800 } 7801 } 7802 } 7803 if (!anyConstrained) { 7804 if (outNumPoints) *outNumPoints = 0; 7805 if (outNumIndices) *outNumIndices = 0; 7806 if (outPoints) *outPoints = NULL; 7807 if (outMat) *outMat = NULL; 7808 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7809 PetscFunctionReturn(PETSC_SUCCESS); 7810 } 7811 7812 if (outNumPoints) *outNumPoints = newNumPoints; 7813 if (outNumIndices) *outNumIndices = newNumIndices; 7814 7815 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7816 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7817 7818 if (!outPoints && !outMat) { 7819 if (offsets) { 7820 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7821 } 7822 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7823 PetscFunctionReturn(PETSC_SUCCESS); 7824 } 7825 7826 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7827 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7828 7829 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7830 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7831 7832 /* output arrays */ 7833 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7834 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7835 7836 // get the new Points 7837 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7838 PetscInt b = points[2 * p]; 7839 PetscInt bDof = 0, bSecDof = 0, bOff; 7840 7841 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7842 if (!bSecDof) continue; 7843 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7844 if (bDof) { 7845 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7846 for (PetscInt q = 0; q < bDof; q++) { 7847 PetscInt a = anchors[bOff + q], aDof = 0; 7848 7849 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7850 if (aDof) { 7851 newPoints[2 * newP] = a; 7852 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7853 newP++; 7854 } 7855 } 7856 } else { 7857 newPoints[2 * newP] = b; 7858 newPoints[2 * newP + 1] = points[2 * p + 1]; 7859 newP++; 7860 } 7861 } 7862 7863 if (outMat) { 7864 PetscScalar *tmpMat; 7865 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7866 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7867 7868 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7869 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7870 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7871 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7872 7873 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7874 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7875 7876 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7877 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7878 7879 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7880 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7881 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7882 // for each field, insert the anchor modification into modMat 7883 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7884 PetscInt fStart = oldOffsets[f]; 7885 PetscInt fNewStart = newOffsets[f]; 7886 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7887 PetscInt b = points[2 * p]; 7888 PetscInt bDof = 0, bSecDof = 0, bOff; 7889 7890 if (b >= sStart && b < sEnd) { 7891 if (numFields) { 7892 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7893 } else { 7894 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7895 } 7896 } 7897 if (!bSecDof) continue; 7898 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7899 if (bDof) { 7900 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7901 for (PetscInt q = 0; q < bDof; q++, newP++) { 7902 PetscInt a = anchors[bOff + q], aDof = 0; 7903 7904 if (a >= sStart && a < sEnd) { 7905 if (numFields) { 7906 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7907 } else { 7908 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7909 } 7910 } 7911 if (aDof) { 7912 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7913 for (PetscInt d = 0; d < bSecDof; d++) { 7914 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7915 } 7916 } 7917 oNew += aDof; 7918 } 7919 } else { 7920 // Insert the identity matrix in this block 7921 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7922 oNew += bSecDof; 7923 newP++; 7924 } 7925 o += bSecDof; 7926 } 7927 } 7928 7929 *outMat = modMat; 7930 7931 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7932 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7933 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7934 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7935 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7936 } 7937 PetscCall(ISRestoreIndices(aIS, &anchors)); 7938 7939 /* output */ 7940 if (outPoints) { 7941 *outPoints = newPoints; 7942 } else { 7943 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7944 } 7945 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7946 PetscFunctionReturn(PETSC_SUCCESS); 7947 } 7948 7949 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) 7950 { 7951 PetscScalar *modMat = NULL; 7952 PetscInt newNumIndices = -1; 7953 7954 PetscFunctionBegin; 7955 /* 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. 7956 modMat is that matrix C */ 7957 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7958 if (outNumIndices) *outNumIndices = newNumIndices; 7959 if (modMat) { 7960 const PetscScalar *newValues = values; 7961 7962 if (multiplyRight) { 7963 PetscScalar *newNewValues = NULL; 7964 PetscBLASInt M, N, K; 7965 PetscScalar a = 1.0, b = 0.0; 7966 7967 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); 7968 7969 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7970 PetscCall(PetscBLASIntCast(numRows, &N)); 7971 PetscCall(PetscBLASIntCast(numIndices, &K)); 7972 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7973 // row-major to column-major conversion, right multiplication becomes left multiplication 7974 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7975 numCols = newNumIndices; 7976 newValues = newNewValues; 7977 } 7978 7979 if (multiplyLeft) { 7980 PetscScalar *newNewValues = NULL; 7981 PetscBLASInt M, N, K; 7982 PetscScalar a = 1.0, b = 0.0; 7983 7984 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); 7985 7986 PetscCall(PetscBLASIntCast(numCols, &M)); 7987 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7988 PetscCall(PetscBLASIntCast(numIndices, &K)); 7989 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7990 // row-major to column-major conversion, left multiplication becomes right multiplication 7991 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7992 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7993 newValues = newNewValues; 7994 } 7995 *outValues = (PetscScalar *)newValues; 7996 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7997 } 7998 PetscFunctionReturn(PETSC_SUCCESS); 7999 } 8000 8001 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) 8002 { 8003 PetscFunctionBegin; 8004 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 8005 PetscFunctionReturn(PETSC_SUCCESS); 8006 } 8007 8008 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 8009 { 8010 /* Closure ordering */ 8011 PetscSection clSection; 8012 IS clPoints; 8013 const PetscInt *clp; 8014 PetscInt *points; 8015 PetscInt Ncl, Ni = 0; 8016 8017 PetscFunctionBeginHot; 8018 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8019 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 8020 PetscInt dof; 8021 8022 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8023 Ni += dof; 8024 } 8025 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8026 *closureSize = Ni; 8027 PetscFunctionReturn(PETSC_SUCCESS); 8028 } 8029 8030 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) 8031 { 8032 /* Closure ordering */ 8033 PetscSection clSection; 8034 IS clPoints; 8035 const PetscInt *clp; 8036 PetscInt *points; 8037 const PetscInt *clperm = NULL; 8038 /* Dof permutation and sign flips */ 8039 const PetscInt **perms[32] = {NULL}; 8040 const PetscScalar **flips[32] = {NULL}; 8041 PetscScalar *valCopy = NULL; 8042 /* Hanging node constraints */ 8043 PetscInt *pointsC = NULL; 8044 PetscScalar *valuesC = NULL; 8045 PetscInt NclC, NiC; 8046 8047 PetscInt *idx; 8048 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8049 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8050 PetscInt idxStart, idxEnd; 8051 PetscInt nRows, nCols; 8052 8053 PetscFunctionBeginHot; 8054 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8055 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8056 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8057 PetscAssertPointer(numRows, 6); 8058 PetscAssertPointer(numCols, 7); 8059 if (indices) PetscAssertPointer(indices, 8); 8060 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8061 if (values) PetscAssertPointer(values, 10); 8062 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8063 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8064 PetscCall(PetscArrayzero(offsets, 32)); 8065 /* 1) Get points in closure */ 8066 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8067 if (useClPerm) { 8068 PetscInt depth, clsize; 8069 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8070 for (clsize = 0, p = 0; p < Ncl; p++) { 8071 PetscInt dof; 8072 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8073 clsize += dof; 8074 } 8075 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8076 } 8077 /* 2) Get number of indices on these points and field offsets from section */ 8078 for (p = 0; p < Ncl * 2; p += 2) { 8079 PetscInt dof, fdof; 8080 8081 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8082 for (f = 0; f < Nf; ++f) { 8083 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8084 offsets[f + 1] += fdof; 8085 } 8086 Ni += dof; 8087 } 8088 if (*numRows == -1) *numRows = Ni; 8089 if (*numCols == -1) *numCols = Ni; 8090 nRows = *numRows; 8091 nCols = *numCols; 8092 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8093 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8094 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8095 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8096 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8097 for (f = 0; f < PetscMax(1, Nf); ++f) { 8098 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8099 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8100 /* may need to apply sign changes to the element matrix */ 8101 if (values && flips[f]) { 8102 PetscInt foffset = offsets[f]; 8103 8104 for (p = 0; p < Ncl; ++p) { 8105 PetscInt pnt = points[2 * p], fdof; 8106 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8107 8108 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8109 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8110 if (flip) { 8111 PetscInt i, j, k; 8112 8113 if (!valCopy) { 8114 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8115 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8116 *values = valCopy; 8117 } 8118 for (i = 0; i < fdof; ++i) { 8119 PetscScalar fval = flip[i]; 8120 8121 if (multiplyRight) { 8122 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8123 } 8124 if (multiplyLeft) { 8125 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8126 } 8127 } 8128 } 8129 foffset += fdof; 8130 } 8131 } 8132 } 8133 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8134 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8135 if (NclC) { 8136 if (multiplyRight) *numCols = NiC; 8137 if (multiplyLeft) *numRows = NiC; 8138 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8139 for (f = 0; f < PetscMax(1, Nf); ++f) { 8140 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8141 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8142 } 8143 for (f = 0; f < PetscMax(1, Nf); ++f) { 8144 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8145 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8146 } 8147 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8148 Ncl = NclC; 8149 Ni = NiC; 8150 points = pointsC; 8151 if (values) *values = valuesC; 8152 } 8153 /* 5) Calculate indices */ 8154 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8155 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8156 if (Nf) { 8157 PetscInt idxOff; 8158 PetscBool useFieldOffsets; 8159 8160 if (outOffsets) { 8161 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8162 } 8163 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8164 if (useFieldOffsets) { 8165 for (p = 0; p < Ncl; ++p) { 8166 const PetscInt pnt = points[p * 2]; 8167 8168 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8169 } 8170 } else { 8171 for (p = 0; p < Ncl; ++p) { 8172 const PetscInt pnt = points[p * 2]; 8173 8174 if (pnt < idxStart || pnt >= idxEnd) continue; 8175 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8176 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8177 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8178 * global section. */ 8179 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8180 } 8181 } 8182 } else { 8183 PetscInt off = 0, idxOff; 8184 8185 for (p = 0; p < Ncl; ++p) { 8186 const PetscInt pnt = points[p * 2]; 8187 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8188 8189 if (pnt < idxStart || pnt >= idxEnd) continue; 8190 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8191 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8192 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8193 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8194 } 8195 } 8196 /* 6) Cleanup */ 8197 for (f = 0; f < PetscMax(1, Nf); ++f) { 8198 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8199 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8200 } 8201 if (NclC) { 8202 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8203 } else { 8204 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8205 } 8206 8207 if (indices) *indices = idx; 8208 PetscFunctionReturn(PETSC_SUCCESS); 8209 } 8210 8211 /*@C 8212 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8213 8214 Not collective 8215 8216 Input Parameters: 8217 + dm - The `DM` 8218 . section - The `PetscSection` describing the points (a local section) 8219 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8220 . point - The point defining the closure 8221 - useClPerm - Use the closure point permutation if available 8222 8223 Output Parameters: 8224 + numIndices - The number of dof indices in the closure of point with the input sections 8225 . indices - The dof indices 8226 . outOffsets - Array to write the field offsets into, or `NULL` 8227 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8228 8229 Level: advanced 8230 8231 Notes: 8232 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8233 8234 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8235 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8236 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8237 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8238 indices (with the above semantics) are implied. 8239 8240 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8241 `PetscSection`, `DMGetGlobalSection()` 8242 @*/ 8243 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8244 { 8245 PetscInt numRows = -1, numCols = -1; 8246 8247 PetscFunctionBeginHot; 8248 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8249 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8250 *numIndices = numRows; 8251 PetscFunctionReturn(PETSC_SUCCESS); 8252 } 8253 8254 /*@C 8255 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8256 8257 Not collective 8258 8259 Input Parameters: 8260 + dm - The `DM` 8261 . section - The `PetscSection` describing the points (a local section) 8262 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8263 . point - The point defining the closure 8264 - useClPerm - Use the closure point permutation if available 8265 8266 Output Parameters: 8267 + numIndices - The number of dof indices in the closure of point with the input sections 8268 . indices - The dof indices 8269 . outOffsets - Array to write the field offsets into, or `NULL` 8270 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8271 8272 Level: advanced 8273 8274 Notes: 8275 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8276 8277 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8278 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8279 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8280 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8281 indices (with the above semantics) are implied. 8282 8283 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8284 @*/ 8285 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8286 { 8287 PetscFunctionBegin; 8288 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8289 PetscAssertPointer(indices, 7); 8290 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8291 PetscFunctionReturn(PETSC_SUCCESS); 8292 } 8293 8294 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8295 { 8296 DM_Plex *mesh = (DM_Plex *)dm->data; 8297 PetscInt *indices; 8298 PetscInt numIndices; 8299 const PetscScalar *valuesOrig = values; 8300 PetscErrorCode ierr; 8301 8302 PetscFunctionBegin; 8303 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8304 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8305 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8306 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8307 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8308 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8309 8310 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8311 8312 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8313 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8314 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8315 if (ierr) { 8316 PetscMPIInt rank; 8317 8318 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8319 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8320 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8321 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8322 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8323 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8324 } 8325 if (mesh->printFEM > 1) { 8326 PetscInt i; 8327 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8328 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8329 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8330 } 8331 8332 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8333 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8334 PetscFunctionReturn(PETSC_SUCCESS); 8335 } 8336 8337 /*@C 8338 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8339 8340 Not collective 8341 8342 Input Parameters: 8343 + dm - The `DM` 8344 . section - The section describing the layout in `v`, or `NULL` to use the default section 8345 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8346 . A - The matrix 8347 . point - The point in the `DM` 8348 . values - The array of values 8349 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8350 8351 Level: intermediate 8352 8353 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8354 @*/ 8355 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8356 { 8357 PetscFunctionBegin; 8358 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8359 PetscFunctionReturn(PETSC_SUCCESS); 8360 } 8361 8362 /*@C 8363 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8364 8365 Not collective 8366 8367 Input Parameters: 8368 + dmRow - The `DM` for the row fields 8369 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8370 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8371 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8372 . dmCol - The `DM` for the column fields 8373 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8374 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8375 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8376 . A - The matrix 8377 . point - The point in the `DM` 8378 . values - The array of values 8379 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8380 8381 Level: intermediate 8382 8383 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8384 @*/ 8385 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) 8386 { 8387 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8388 PetscInt *indicesRow, *indicesCol; 8389 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8390 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8391 8392 PetscErrorCode ierr; 8393 8394 PetscFunctionBegin; 8395 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8396 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8397 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8398 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8399 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8400 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8401 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8402 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8403 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8404 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8405 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8406 8407 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8408 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8409 valuesV1 = valuesV0; 8410 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8411 valuesV2 = valuesV1; 8412 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8413 8414 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8415 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8416 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8417 if (ierr) { 8418 PetscMPIInt rank; 8419 8420 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8421 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8422 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8423 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8424 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8425 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8426 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8427 } 8428 8429 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8430 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8431 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8432 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8433 PetscFunctionReturn(PETSC_SUCCESS); 8434 } 8435 8436 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8437 { 8438 DM_Plex *mesh = (DM_Plex *)dmf->data; 8439 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8440 PetscInt *cpoints = NULL; 8441 PetscInt *findices, *cindices; 8442 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8443 PetscInt foffsets[32], coffsets[32]; 8444 DMPolytopeType ct; 8445 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8446 PetscErrorCode ierr; 8447 8448 PetscFunctionBegin; 8449 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8450 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8451 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8452 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8453 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8454 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8455 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8456 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8457 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8458 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8459 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8460 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8461 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8462 PetscCall(PetscArrayzero(foffsets, 32)); 8463 PetscCall(PetscArrayzero(coffsets, 32)); 8464 /* Column indices */ 8465 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8466 maxFPoints = numCPoints; 8467 /* Compress out points not in the section */ 8468 /* TODO: Squeeze out points with 0 dof as well */ 8469 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8470 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8471 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8472 cpoints[q * 2] = cpoints[p]; 8473 cpoints[q * 2 + 1] = cpoints[p + 1]; 8474 ++q; 8475 } 8476 } 8477 numCPoints = q; 8478 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8479 PetscInt fdof; 8480 8481 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8482 if (!dof) continue; 8483 for (f = 0; f < numFields; ++f) { 8484 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8485 coffsets[f + 1] += fdof; 8486 } 8487 numCIndices += dof; 8488 } 8489 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8490 /* Row indices */ 8491 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8492 { 8493 DMPlexTransform tr; 8494 DMPolytopeType *rct; 8495 PetscInt *rsize, *rcone, *rornt, Nt; 8496 8497 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8498 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8499 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8500 numSubcells = rsize[Nt - 1]; 8501 PetscCall(DMPlexTransformDestroy(&tr)); 8502 } 8503 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8504 for (r = 0, q = 0; r < numSubcells; ++r) { 8505 /* TODO Map from coarse to fine cells */ 8506 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8507 /* Compress out points not in the section */ 8508 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8509 for (p = 0; p < numFPoints * 2; p += 2) { 8510 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8511 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8512 if (!dof) continue; 8513 for (s = 0; s < q; ++s) 8514 if (fpoints[p] == ftotpoints[s * 2]) break; 8515 if (s < q) continue; 8516 ftotpoints[q * 2] = fpoints[p]; 8517 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8518 ++q; 8519 } 8520 } 8521 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8522 } 8523 numFPoints = q; 8524 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8525 PetscInt fdof; 8526 8527 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8528 if (!dof) continue; 8529 for (f = 0; f < numFields; ++f) { 8530 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8531 foffsets[f + 1] += fdof; 8532 } 8533 numFIndices += dof; 8534 } 8535 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8536 8537 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8538 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8539 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8540 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8541 if (numFields) { 8542 const PetscInt **permsF[32] = {NULL}; 8543 const PetscInt **permsC[32] = {NULL}; 8544 8545 for (f = 0; f < numFields; f++) { 8546 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8547 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8548 } 8549 for (p = 0; p < numFPoints; p++) { 8550 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8551 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8552 } 8553 for (p = 0; p < numCPoints; p++) { 8554 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8555 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8556 } 8557 for (f = 0; f < numFields; f++) { 8558 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8559 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8560 } 8561 } else { 8562 const PetscInt **permsF = NULL; 8563 const PetscInt **permsC = NULL; 8564 8565 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8566 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8567 for (p = 0, off = 0; p < numFPoints; p++) { 8568 const PetscInt *perm = permsF ? permsF[p] : NULL; 8569 8570 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8571 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8572 } 8573 for (p = 0, off = 0; p < numCPoints; p++) { 8574 const PetscInt *perm = permsC ? permsC[p] : NULL; 8575 8576 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8577 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8578 } 8579 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8580 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8581 } 8582 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8583 /* TODO: flips */ 8584 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8585 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8586 if (ierr) { 8587 PetscMPIInt rank; 8588 8589 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8590 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8591 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8592 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8593 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8594 } 8595 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8596 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8597 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8598 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8599 PetscFunctionReturn(PETSC_SUCCESS); 8600 } 8601 8602 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8603 { 8604 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8605 PetscInt *cpoints = NULL; 8606 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8607 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8608 DMPolytopeType ct; 8609 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8610 8611 PetscFunctionBegin; 8612 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8613 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8614 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8615 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8616 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8617 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8618 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8619 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8620 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8621 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8622 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8623 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8624 /* Column indices */ 8625 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8626 maxFPoints = numCPoints; 8627 /* Compress out points not in the section */ 8628 /* TODO: Squeeze out points with 0 dof as well */ 8629 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8630 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8631 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8632 cpoints[q * 2] = cpoints[p]; 8633 cpoints[q * 2 + 1] = cpoints[p + 1]; 8634 ++q; 8635 } 8636 } 8637 numCPoints = q; 8638 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8639 PetscInt fdof; 8640 8641 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8642 if (!dof) continue; 8643 for (f = 0; f < numFields; ++f) { 8644 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8645 coffsets[f + 1] += fdof; 8646 } 8647 numCIndices += dof; 8648 } 8649 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8650 /* Row indices */ 8651 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8652 { 8653 DMPlexTransform tr; 8654 DMPolytopeType *rct; 8655 PetscInt *rsize, *rcone, *rornt, Nt; 8656 8657 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8658 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8659 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8660 numSubcells = rsize[Nt - 1]; 8661 PetscCall(DMPlexTransformDestroy(&tr)); 8662 } 8663 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8664 for (r = 0, q = 0; r < numSubcells; ++r) { 8665 /* TODO Map from coarse to fine cells */ 8666 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8667 /* Compress out points not in the section */ 8668 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8669 for (p = 0; p < numFPoints * 2; p += 2) { 8670 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8671 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8672 if (!dof) continue; 8673 for (s = 0; s < q; ++s) 8674 if (fpoints[p] == ftotpoints[s * 2]) break; 8675 if (s < q) continue; 8676 ftotpoints[q * 2] = fpoints[p]; 8677 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8678 ++q; 8679 } 8680 } 8681 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8682 } 8683 numFPoints = q; 8684 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8685 PetscInt fdof; 8686 8687 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8688 if (!dof) continue; 8689 for (f = 0; f < numFields; ++f) { 8690 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8691 foffsets[f + 1] += fdof; 8692 } 8693 numFIndices += dof; 8694 } 8695 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8696 8697 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8698 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8699 if (numFields) { 8700 const PetscInt **permsF[32] = {NULL}; 8701 const PetscInt **permsC[32] = {NULL}; 8702 8703 for (f = 0; f < numFields; f++) { 8704 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8705 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8706 } 8707 for (p = 0; p < numFPoints; p++) { 8708 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8709 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8710 } 8711 for (p = 0; p < numCPoints; p++) { 8712 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8713 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8714 } 8715 for (f = 0; f < numFields; f++) { 8716 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8717 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8718 } 8719 } else { 8720 const PetscInt **permsF = NULL; 8721 const PetscInt **permsC = NULL; 8722 8723 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8724 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8725 for (p = 0, off = 0; p < numFPoints; p++) { 8726 const PetscInt *perm = permsF ? permsF[p] : NULL; 8727 8728 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8729 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8730 } 8731 for (p = 0, off = 0; p < numCPoints; p++) { 8732 const PetscInt *perm = permsC ? permsC[p] : NULL; 8733 8734 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8735 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8736 } 8737 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8738 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8739 } 8740 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8741 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8742 PetscFunctionReturn(PETSC_SUCCESS); 8743 } 8744 8745 /*@ 8746 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8747 8748 Input Parameter: 8749 . dm - The `DMPLEX` object 8750 8751 Output Parameter: 8752 . cellHeight - The height of a cell 8753 8754 Level: developer 8755 8756 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8757 @*/ 8758 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8759 { 8760 DM_Plex *mesh = (DM_Plex *)dm->data; 8761 8762 PetscFunctionBegin; 8763 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8764 PetscAssertPointer(cellHeight, 2); 8765 *cellHeight = mesh->vtkCellHeight; 8766 PetscFunctionReturn(PETSC_SUCCESS); 8767 } 8768 8769 /*@ 8770 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8771 8772 Input Parameters: 8773 + dm - The `DMPLEX` object 8774 - cellHeight - The height of a cell 8775 8776 Level: developer 8777 8778 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8779 @*/ 8780 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8781 { 8782 DM_Plex *mesh = (DM_Plex *)dm->data; 8783 8784 PetscFunctionBegin; 8785 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8786 mesh->vtkCellHeight = cellHeight; 8787 PetscFunctionReturn(PETSC_SUCCESS); 8788 } 8789 8790 /*@ 8791 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8792 8793 Input Parameters: 8794 + dm - The `DMPLEX` object 8795 - ct - The `DMPolytopeType` of the cell 8796 8797 Output Parameters: 8798 + start - The first cell of this type, or `NULL` 8799 - end - The upper bound on this celltype, or `NULL` 8800 8801 Level: advanced 8802 8803 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8804 @*/ 8805 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end) 8806 { 8807 DM_Plex *mesh = (DM_Plex *)dm->data; 8808 DMLabel label; 8809 PetscInt pStart, pEnd; 8810 8811 PetscFunctionBegin; 8812 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8813 if (start) { 8814 PetscAssertPointer(start, 3); 8815 *start = 0; 8816 } 8817 if (end) { 8818 PetscAssertPointer(end, 4); 8819 *end = 0; 8820 } 8821 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8822 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8823 if (mesh->tr) { 8824 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8825 } else { 8826 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8827 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8828 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8829 } 8830 PetscFunctionReturn(PETSC_SUCCESS); 8831 } 8832 8833 /*@ 8834 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8835 8836 Input Parameters: 8837 + dm - The `DMPLEX` object 8838 - depth - The depth for the given point stratum 8839 8840 Output Parameter: 8841 . gsize - The global number of points in the stratum 8842 8843 Level: advanced 8844 8845 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8846 @*/ 8847 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8848 { 8849 PetscSF sf; 8850 const PetscInt *leaves; 8851 PetscInt Nl, loc, start, end, lsize = 0; 8852 8853 PetscFunctionBegin; 8854 PetscCall(DMGetPointSF(dm, &sf)); 8855 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8856 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8857 for (PetscInt p = start; p < end; ++p) { 8858 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8859 if (loc < 0) ++lsize; 8860 } 8861 PetscCallMPI(MPI_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8862 PetscFunctionReturn(PETSC_SUCCESS); 8863 } 8864 8865 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8866 { 8867 PetscSection section, globalSection; 8868 PetscInt *numbers, p; 8869 8870 PetscFunctionBegin; 8871 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8872 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8873 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8874 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8875 PetscCall(PetscSectionSetUp(section)); 8876 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8877 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8878 for (p = pStart; p < pEnd; ++p) { 8879 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8880 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8881 else numbers[p - pStart] += shift; 8882 } 8883 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8884 if (globalSize) { 8885 PetscLayout layout; 8886 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8887 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8888 PetscCall(PetscLayoutDestroy(&layout)); 8889 } 8890 PetscCall(PetscSectionDestroy(§ion)); 8891 PetscCall(PetscSectionDestroy(&globalSection)); 8892 PetscFunctionReturn(PETSC_SUCCESS); 8893 } 8894 8895 /*@ 8896 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8897 8898 Input Parameters: 8899 + dm - The `DMPLEX` object 8900 - includeAll - Whether to include all cells, or just the simplex and box cells 8901 8902 Output Parameter: 8903 . globalCellNumbers - Global cell numbers for all cells on this process 8904 8905 Level: developer 8906 8907 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8908 @*/ 8909 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8910 { 8911 PetscInt cellHeight, cStart, cEnd; 8912 8913 PetscFunctionBegin; 8914 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8915 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8916 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8917 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8918 PetscFunctionReturn(PETSC_SUCCESS); 8919 } 8920 8921 /*@ 8922 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8923 8924 Input Parameter: 8925 . dm - The `DMPLEX` object 8926 8927 Output Parameter: 8928 . globalCellNumbers - Global cell numbers for all cells on this process 8929 8930 Level: developer 8931 8932 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8933 @*/ 8934 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8935 { 8936 DM_Plex *mesh = (DM_Plex *)dm->data; 8937 8938 PetscFunctionBegin; 8939 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8940 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8941 *globalCellNumbers = mesh->globalCellNumbers; 8942 PetscFunctionReturn(PETSC_SUCCESS); 8943 } 8944 8945 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8946 { 8947 PetscInt vStart, vEnd; 8948 8949 PetscFunctionBegin; 8950 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8951 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8952 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8953 PetscFunctionReturn(PETSC_SUCCESS); 8954 } 8955 8956 /*@ 8957 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8958 8959 Input Parameter: 8960 . dm - The `DMPLEX` object 8961 8962 Output Parameter: 8963 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8964 8965 Level: developer 8966 8967 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8968 @*/ 8969 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8970 { 8971 DM_Plex *mesh = (DM_Plex *)dm->data; 8972 8973 PetscFunctionBegin; 8974 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8975 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8976 *globalVertexNumbers = mesh->globalVertexNumbers; 8977 PetscFunctionReturn(PETSC_SUCCESS); 8978 } 8979 8980 /*@ 8981 DMPlexCreatePointNumbering - Create a global numbering for all points. 8982 8983 Collective 8984 8985 Input Parameter: 8986 . dm - The `DMPLEX` object 8987 8988 Output Parameter: 8989 . globalPointNumbers - Global numbers for all points on this process 8990 8991 Level: developer 8992 8993 Notes: 8994 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8995 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8996 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8997 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8998 8999 The partitioned mesh is 9000 ``` 9001 (2)--0--(3)--1--(4) (1)--0--(2) 9002 ``` 9003 and its global numbering is 9004 ``` 9005 (3)--0--(4)--1--(5)--2--(6) 9006 ``` 9007 Then the global numbering is provided as 9008 ``` 9009 [0] Number of indices in set 5 9010 [0] 0 0 9011 [0] 1 1 9012 [0] 2 3 9013 [0] 3 4 9014 [0] 4 -6 9015 [1] Number of indices in set 3 9016 [1] 0 2 9017 [1] 1 5 9018 [1] 2 6 9019 ``` 9020 9021 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9022 @*/ 9023 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 9024 { 9025 IS nums[4]; 9026 PetscInt depths[4], gdepths[4], starts[4]; 9027 PetscInt depth, d, shift = 0; 9028 PetscBool empty = PETSC_FALSE; 9029 9030 PetscFunctionBegin; 9031 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9032 PetscCall(DMPlexGetDepth(dm, &depth)); 9033 // For unstratified meshes use dim instead of depth 9034 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9035 // If any stratum is empty, we must mark all empty 9036 for (d = 0; d <= depth; ++d) { 9037 PetscInt end; 9038 9039 depths[d] = depth - d; 9040 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9041 if (!(starts[d] - end)) empty = PETSC_TRUE; 9042 } 9043 if (empty) 9044 for (d = 0; d <= depth; ++d) { 9045 depths[d] = -1; 9046 starts[d] = -1; 9047 } 9048 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9049 PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9050 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]); 9051 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9052 for (d = 0; d <= depth; ++d) { 9053 PetscInt pStart, pEnd, gsize; 9054 9055 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9056 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9057 shift += gsize; 9058 } 9059 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9060 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9061 PetscFunctionReturn(PETSC_SUCCESS); 9062 } 9063 9064 /*@ 9065 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9066 9067 Collective 9068 9069 Input Parameter: 9070 . dm - The `DMPLEX` object 9071 9072 Output Parameter: 9073 . globalEdgeNumbers - Global numbers for all edges on this process 9074 9075 Level: developer 9076 9077 Notes: 9078 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). 9079 9080 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9081 @*/ 9082 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9083 { 9084 PetscSF sf; 9085 PetscInt eStart, eEnd; 9086 9087 PetscFunctionBegin; 9088 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9089 PetscCall(DMGetPointSF(dm, &sf)); 9090 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9091 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9092 PetscFunctionReturn(PETSC_SUCCESS); 9093 } 9094 9095 /*@ 9096 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9097 9098 Input Parameter: 9099 . dm - The `DMPLEX` object 9100 9101 Output Parameter: 9102 . ranks - The rank field 9103 9104 Options Database Key: 9105 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9106 9107 Level: intermediate 9108 9109 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9110 @*/ 9111 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9112 { 9113 DM rdm; 9114 PetscFE fe; 9115 PetscScalar *r; 9116 PetscMPIInt rank; 9117 DMPolytopeType ct; 9118 PetscInt dim, cStart, cEnd, c; 9119 PetscBool simplex; 9120 9121 PetscFunctionBeginUser; 9122 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9123 PetscAssertPointer(ranks, 2); 9124 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9125 PetscCall(DMClone(dm, &rdm)); 9126 PetscCall(DMGetDimension(rdm, &dim)); 9127 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9128 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9129 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9130 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9131 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9132 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9133 PetscCall(PetscFEDestroy(&fe)); 9134 PetscCall(DMCreateDS(rdm)); 9135 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9136 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9137 PetscCall(VecGetArray(*ranks, &r)); 9138 for (c = cStart; c < cEnd; ++c) { 9139 PetscScalar *lr; 9140 9141 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9142 if (lr) *lr = rank; 9143 } 9144 PetscCall(VecRestoreArray(*ranks, &r)); 9145 PetscCall(DMDestroy(&rdm)); 9146 PetscFunctionReturn(PETSC_SUCCESS); 9147 } 9148 9149 /*@ 9150 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9151 9152 Input Parameters: 9153 + dm - The `DMPLEX` 9154 - label - The `DMLabel` 9155 9156 Output Parameter: 9157 . val - The label value field 9158 9159 Options Database Key: 9160 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9161 9162 Level: intermediate 9163 9164 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9165 @*/ 9166 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9167 { 9168 DM rdm, plex; 9169 Vec lval; 9170 PetscSection section; 9171 PetscFE fe; 9172 PetscScalar *v; 9173 PetscInt dim, pStart, pEnd, p, cStart; 9174 DMPolytopeType ct; 9175 char name[PETSC_MAX_PATH_LEN]; 9176 const char *lname, *prefix; 9177 9178 PetscFunctionBeginUser; 9179 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9180 PetscAssertPointer(label, 2); 9181 PetscAssertPointer(val, 3); 9182 PetscCall(DMClone(dm, &rdm)); 9183 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9184 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9185 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9186 PetscCall(DMDestroy(&plex)); 9187 PetscCall(DMGetDimension(rdm, &dim)); 9188 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9189 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9190 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9191 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9192 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9193 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9194 PetscCall(PetscFEDestroy(&fe)); 9195 PetscCall(DMCreateDS(rdm)); 9196 PetscCall(DMCreateGlobalVector(rdm, val)); 9197 PetscCall(DMCreateLocalVector(rdm, &lval)); 9198 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9199 PetscCall(DMGetLocalSection(rdm, §ion)); 9200 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9201 PetscCall(VecGetArray(lval, &v)); 9202 for (p = pStart; p < pEnd; ++p) { 9203 PetscInt cval, dof, off; 9204 9205 PetscCall(PetscSectionGetDof(section, p, &dof)); 9206 if (!dof) continue; 9207 PetscCall(DMLabelGetValue(label, p, &cval)); 9208 PetscCall(PetscSectionGetOffset(section, p, &off)); 9209 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9210 } 9211 PetscCall(VecRestoreArray(lval, &v)); 9212 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9213 PetscCall(VecDestroy(&lval)); 9214 PetscCall(DMDestroy(&rdm)); 9215 PetscFunctionReturn(PETSC_SUCCESS); 9216 } 9217 9218 /*@ 9219 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9220 9221 Input Parameter: 9222 . dm - The `DMPLEX` object 9223 9224 Level: developer 9225 9226 Notes: 9227 This is a useful diagnostic when creating meshes programmatically. 9228 9229 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9230 9231 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9232 @*/ 9233 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9234 { 9235 PetscSection coneSection, supportSection; 9236 const PetscInt *cone, *support; 9237 PetscInt coneSize, c, supportSize, s; 9238 PetscInt pStart, pEnd, p, pp, csize, ssize; 9239 PetscBool storagecheck = PETSC_TRUE; 9240 9241 PetscFunctionBegin; 9242 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9243 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9244 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9245 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9246 /* Check that point p is found in the support of its cone points, and vice versa */ 9247 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9248 for (p = pStart; p < pEnd; ++p) { 9249 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9250 PetscCall(DMPlexGetCone(dm, p, &cone)); 9251 for (c = 0; c < coneSize; ++c) { 9252 PetscBool dup = PETSC_FALSE; 9253 PetscInt d; 9254 for (d = c - 1; d >= 0; --d) { 9255 if (cone[c] == cone[d]) { 9256 dup = PETSC_TRUE; 9257 break; 9258 } 9259 } 9260 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9261 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9262 for (s = 0; s < supportSize; ++s) { 9263 if (support[s] == p) break; 9264 } 9265 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9266 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9267 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9268 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9269 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9270 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9271 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9272 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]); 9273 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9274 } 9275 } 9276 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9277 if (p != pp) { 9278 storagecheck = PETSC_FALSE; 9279 continue; 9280 } 9281 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9282 PetscCall(DMPlexGetSupport(dm, p, &support)); 9283 for (s = 0; s < supportSize; ++s) { 9284 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9285 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9286 for (c = 0; c < coneSize; ++c) { 9287 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9288 if (cone[c] != pp) { 9289 c = 0; 9290 break; 9291 } 9292 if (cone[c] == p) break; 9293 } 9294 if (c >= coneSize) { 9295 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9296 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9297 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9298 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9299 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9300 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9301 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9302 } 9303 } 9304 } 9305 if (storagecheck) { 9306 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9307 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9308 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9309 } 9310 PetscFunctionReturn(PETSC_SUCCESS); 9311 } 9312 9313 /* 9314 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. 9315 */ 9316 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9317 { 9318 DMPolytopeType cct; 9319 PetscInt ptpoints[4]; 9320 const PetscInt *cone, *ccone, *ptcone; 9321 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9322 9323 PetscFunctionBegin; 9324 *unsplit = 0; 9325 switch (ct) { 9326 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9327 ptpoints[npt++] = c; 9328 break; 9329 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9330 PetscCall(DMPlexGetCone(dm, c, &cone)); 9331 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9332 for (cp = 0; cp < coneSize; ++cp) { 9333 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9334 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9335 } 9336 break; 9337 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9338 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9339 PetscCall(DMPlexGetCone(dm, c, &cone)); 9340 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9341 for (cp = 0; cp < coneSize; ++cp) { 9342 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9343 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9344 for (ccp = 0; ccp < cconeSize; ++ccp) { 9345 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9346 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9347 PetscInt p; 9348 for (p = 0; p < npt; ++p) 9349 if (ptpoints[p] == ccone[ccp]) break; 9350 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9351 } 9352 } 9353 } 9354 break; 9355 default: 9356 break; 9357 } 9358 for (pt = 0; pt < npt; ++pt) { 9359 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9360 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9361 } 9362 PetscFunctionReturn(PETSC_SUCCESS); 9363 } 9364 9365 /*@ 9366 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9367 9368 Input Parameters: 9369 + dm - The `DMPLEX` object 9370 - cellHeight - Normally 0 9371 9372 Level: developer 9373 9374 Notes: 9375 This is a useful diagnostic when creating meshes programmatically. 9376 Currently applicable only to homogeneous simplex or tensor meshes. 9377 9378 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9379 9380 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9381 @*/ 9382 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9383 { 9384 DMPlexInterpolatedFlag interp; 9385 DMPolytopeType ct; 9386 PetscInt vStart, vEnd, cStart, cEnd, c; 9387 9388 PetscFunctionBegin; 9389 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9390 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9391 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9392 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9393 for (c = cStart; c < cEnd; ++c) { 9394 PetscInt *closure = NULL; 9395 PetscInt coneSize, closureSize, cl, Nv = 0; 9396 9397 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9398 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9399 if (interp == DMPLEX_INTERPOLATED_FULL) { 9400 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9401 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)); 9402 } 9403 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9404 for (cl = 0; cl < closureSize * 2; cl += 2) { 9405 const PetscInt p = closure[cl]; 9406 if ((p >= vStart) && (p < vEnd)) ++Nv; 9407 } 9408 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9409 /* Special Case: Tensor faces with identified vertices */ 9410 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9411 PetscInt unsplit; 9412 9413 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9414 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9415 } 9416 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)); 9417 } 9418 PetscFunctionReturn(PETSC_SUCCESS); 9419 } 9420 9421 /*@ 9422 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9423 9424 Collective 9425 9426 Input Parameters: 9427 + dm - The `DMPLEX` object 9428 - cellHeight - Normally 0 9429 9430 Level: developer 9431 9432 Notes: 9433 This is a useful diagnostic when creating meshes programmatically. 9434 This routine is only relevant for meshes that are fully interpolated across all ranks. 9435 It will error out if a partially interpolated mesh is given on some rank. 9436 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9437 9438 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9439 9440 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9441 @*/ 9442 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9443 { 9444 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9445 DMPlexInterpolatedFlag interpEnum; 9446 9447 PetscFunctionBegin; 9448 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9449 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9450 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9451 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9452 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9453 PetscFunctionReturn(PETSC_SUCCESS); 9454 } 9455 9456 PetscCall(DMGetDimension(dm, &dim)); 9457 PetscCall(DMPlexGetDepth(dm, &depth)); 9458 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9459 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9460 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9461 for (c = cStart; c < cEnd; ++c) { 9462 const PetscInt *cone, *ornt, *faceSizes, *faces; 9463 const DMPolytopeType *faceTypes; 9464 DMPolytopeType ct; 9465 PetscInt numFaces, coneSize, f; 9466 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9467 9468 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9469 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9470 if (unsplit) continue; 9471 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9472 PetscCall(DMPlexGetCone(dm, c, &cone)); 9473 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9474 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9475 for (cl = 0; cl < closureSize * 2; cl += 2) { 9476 const PetscInt p = closure[cl]; 9477 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9478 } 9479 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9480 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); 9481 for (f = 0; f < numFaces; ++f) { 9482 DMPolytopeType fct; 9483 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9484 9485 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9486 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9487 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9488 const PetscInt p = fclosure[cl]; 9489 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9490 } 9491 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]); 9492 for (v = 0; v < fnumCorners; ++v) { 9493 if (fclosure[v] != faces[fOff + v]) { 9494 PetscInt v1; 9495 9496 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9497 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9498 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9499 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9500 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9501 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]); 9502 } 9503 } 9504 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9505 fOff += faceSizes[f]; 9506 } 9507 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9508 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9509 } 9510 } 9511 PetscFunctionReturn(PETSC_SUCCESS); 9512 } 9513 9514 /*@ 9515 DMPlexCheckGeometry - Check the geometry of mesh cells 9516 9517 Input Parameter: 9518 . dm - The `DMPLEX` object 9519 9520 Level: developer 9521 9522 Notes: 9523 This is a useful diagnostic when creating meshes programmatically. 9524 9525 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9526 9527 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9528 @*/ 9529 PetscErrorCode DMPlexCheckGeometry(DM dm) 9530 { 9531 Vec coordinates; 9532 PetscReal detJ, J[9], refVol = 1.0; 9533 PetscReal vol; 9534 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9535 9536 PetscFunctionBegin; 9537 PetscCall(DMGetDimension(dm, &dim)); 9538 PetscCall(DMGetCoordinateDim(dm, &dE)); 9539 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9540 PetscCall(DMPlexGetDepth(dm, &depth)); 9541 for (d = 0; d < dim; ++d) refVol *= 2.0; 9542 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9543 /* Make sure local coordinates are created, because that step is collective */ 9544 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9545 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9546 for (c = cStart; c < cEnd; ++c) { 9547 DMPolytopeType ct; 9548 PetscInt unsplit; 9549 PetscBool ignoreZeroVol = PETSC_FALSE; 9550 9551 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9552 switch (ct) { 9553 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9554 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9555 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9556 ignoreZeroVol = PETSC_TRUE; 9557 break; 9558 default: 9559 break; 9560 } 9561 switch (ct) { 9562 case DM_POLYTOPE_TRI_PRISM: 9563 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9564 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9565 case DM_POLYTOPE_PYRAMID: 9566 continue; 9567 default: 9568 break; 9569 } 9570 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9571 if (unsplit) continue; 9572 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9573 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); 9574 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9575 /* This should work with periodicity since DG coordinates should be used */ 9576 if (depth > 1) { 9577 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9578 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); 9579 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9580 } 9581 } 9582 PetscFunctionReturn(PETSC_SUCCESS); 9583 } 9584 9585 /*@ 9586 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9587 9588 Collective 9589 9590 Input Parameters: 9591 + dm - The `DMPLEX` object 9592 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9593 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9594 9595 Level: developer 9596 9597 Notes: 9598 This is mainly intended for debugging/testing purposes. 9599 9600 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9601 9602 Extra roots can come from periodic cuts, where additional points appear on the boundary 9603 9604 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9605 @*/ 9606 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9607 { 9608 PetscInt l, nleaves, nroots, overlap; 9609 const PetscInt *locals; 9610 const PetscSFNode *remotes; 9611 PetscBool distributed; 9612 MPI_Comm comm; 9613 PetscMPIInt rank; 9614 9615 PetscFunctionBegin; 9616 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9617 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9618 else pointSF = dm->sf; 9619 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9620 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9621 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9622 { 9623 PetscMPIInt mpiFlag; 9624 9625 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9626 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9627 } 9628 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9629 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9630 if (!distributed) { 9631 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); 9632 PetscFunctionReturn(PETSC_SUCCESS); 9633 } 9634 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); 9635 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9636 9637 /* Check SF graph is compatible with DMPlex chart */ 9638 { 9639 PetscInt pStart, pEnd, maxLeaf; 9640 9641 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9642 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9643 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9644 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9645 } 9646 9647 /* Check there are no cells in interface */ 9648 if (!overlap) { 9649 PetscInt cellHeight, cStart, cEnd; 9650 9651 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9652 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9653 for (l = 0; l < nleaves; ++l) { 9654 const PetscInt point = locals ? locals[l] : l; 9655 9656 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9657 } 9658 } 9659 9660 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9661 { 9662 const PetscInt *rootdegree; 9663 9664 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9665 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9666 for (l = 0; l < nleaves; ++l) { 9667 const PetscInt point = locals ? locals[l] : l; 9668 const PetscInt *cone; 9669 PetscInt coneSize, c, idx; 9670 9671 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9672 PetscCall(DMPlexGetCone(dm, point, &cone)); 9673 for (c = 0; c < coneSize; ++c) { 9674 if (!rootdegree[cone[c]]) { 9675 if (locals) { 9676 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9677 } else { 9678 idx = (cone[c] < nleaves) ? cone[c] : -1; 9679 } 9680 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9681 } 9682 } 9683 } 9684 } 9685 PetscFunctionReturn(PETSC_SUCCESS); 9686 } 9687 9688 /*@ 9689 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9690 9691 Collective 9692 9693 Input Parameter: 9694 . dm - The `DMPLEX` object 9695 9696 Level: developer 9697 9698 Notes: 9699 This is mainly intended for debugging/testing purposes. 9700 9701 Other cell types which are disconnected would be caught by the symmetry and face checks. 9702 9703 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9704 9705 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9706 @*/ 9707 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9708 { 9709 PetscInt pStart, pEnd, vStart, vEnd; 9710 9711 PetscFunctionBegin; 9712 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9713 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9714 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9715 for (PetscInt v = vStart; v < vEnd; ++v) { 9716 PetscInt suppSize; 9717 9718 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9719 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9720 } 9721 PetscFunctionReturn(PETSC_SUCCESS); 9722 } 9723 9724 /*@ 9725 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9726 9727 Input Parameter: 9728 . dm - The `DMPLEX` object 9729 9730 Level: developer 9731 9732 Notes: 9733 This is a useful diagnostic when creating meshes programmatically. 9734 9735 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9736 9737 Currently does not include `DMPlexCheckCellShape()`. 9738 9739 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9740 @*/ 9741 PetscErrorCode DMPlexCheck(DM dm) 9742 { 9743 PetscInt cellHeight; 9744 9745 PetscFunctionBegin; 9746 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9747 PetscCall(DMPlexCheckSymmetry(dm)); 9748 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9749 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9750 PetscCall(DMPlexCheckGeometry(dm)); 9751 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9752 PetscCall(DMPlexCheckInterfaceCones(dm)); 9753 PetscCall(DMPlexCheckOrphanVertices(dm)); 9754 PetscFunctionReturn(PETSC_SUCCESS); 9755 } 9756 9757 typedef struct cell_stats { 9758 PetscReal min, max, sum, squaresum; 9759 PetscInt count; 9760 } cell_stats_t; 9761 9762 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9763 { 9764 PetscInt i, N = *len; 9765 9766 for (i = 0; i < N; i++) { 9767 cell_stats_t *A = (cell_stats_t *)a; 9768 cell_stats_t *B = (cell_stats_t *)b; 9769 9770 B->min = PetscMin(A->min, B->min); 9771 B->max = PetscMax(A->max, B->max); 9772 B->sum += A->sum; 9773 B->squaresum += A->squaresum; 9774 B->count += A->count; 9775 } 9776 } 9777 9778 /*@ 9779 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9780 9781 Collective 9782 9783 Input Parameters: 9784 + dm - The `DMPLEX` object 9785 . output - If true, statistics will be displayed on `stdout` 9786 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9787 9788 Level: developer 9789 9790 Notes: 9791 This is mainly intended for debugging/testing purposes. 9792 9793 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9794 9795 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9796 @*/ 9797 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9798 { 9799 DM dmCoarse; 9800 cell_stats_t stats, globalStats; 9801 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9802 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9803 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9804 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9805 PetscMPIInt rank, size; 9806 9807 PetscFunctionBegin; 9808 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9809 stats.min = PETSC_MAX_REAL; 9810 stats.max = PETSC_MIN_REAL; 9811 stats.sum = stats.squaresum = 0.; 9812 stats.count = 0; 9813 9814 PetscCallMPI(MPI_Comm_size(comm, &size)); 9815 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9816 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9817 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9818 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9819 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9820 for (c = cStart; c < cEnd; c++) { 9821 PetscInt i; 9822 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9823 9824 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9825 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9826 for (i = 0; i < PetscSqr(cdim); ++i) { 9827 frobJ += J[i] * J[i]; 9828 frobInvJ += invJ[i] * invJ[i]; 9829 } 9830 cond2 = frobJ * frobInvJ; 9831 cond = PetscSqrtReal(cond2); 9832 9833 stats.min = PetscMin(stats.min, cond); 9834 stats.max = PetscMax(stats.max, cond); 9835 stats.sum += cond; 9836 stats.squaresum += cond2; 9837 stats.count++; 9838 if (output && cond > limit) { 9839 PetscSection coordSection; 9840 Vec coordsLocal; 9841 PetscScalar *coords = NULL; 9842 PetscInt Nv, d, clSize, cl, *closure = NULL; 9843 9844 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9845 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9846 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9847 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9848 for (i = 0; i < Nv / cdim; ++i) { 9849 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9850 for (d = 0; d < cdim; ++d) { 9851 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9852 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9853 } 9854 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9855 } 9856 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9857 for (cl = 0; cl < clSize * 2; cl += 2) { 9858 const PetscInt edge = closure[cl]; 9859 9860 if ((edge >= eStart) && (edge < eEnd)) { 9861 PetscReal len; 9862 9863 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9864 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9865 } 9866 } 9867 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9868 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9869 } 9870 } 9871 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9872 9873 if (size > 1) { 9874 PetscMPIInt blockLengths[2] = {4, 1}; 9875 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9876 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9877 MPI_Op statReduce; 9878 9879 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9880 PetscCallMPI(MPI_Type_commit(&statType)); 9881 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9882 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9883 PetscCallMPI(MPI_Op_free(&statReduce)); 9884 PetscCallMPI(MPI_Type_free(&statType)); 9885 } else { 9886 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9887 } 9888 if (rank == 0) { 9889 count = globalStats.count; 9890 min = globalStats.min; 9891 max = globalStats.max; 9892 mean = globalStats.sum / globalStats.count; 9893 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9894 } 9895 9896 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)); 9897 PetscCall(PetscFree2(J, invJ)); 9898 9899 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9900 if (dmCoarse) { 9901 PetscBool isplex; 9902 9903 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9904 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9905 } 9906 PetscFunctionReturn(PETSC_SUCCESS); 9907 } 9908 9909 /*@ 9910 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9911 orthogonal quality below given tolerance. 9912 9913 Collective 9914 9915 Input Parameters: 9916 + dm - The `DMPLEX` object 9917 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9918 - atol - [0, 1] Absolute tolerance for tagging cells. 9919 9920 Output Parameters: 9921 + OrthQual - `Vec` containing orthogonal quality per cell 9922 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9923 9924 Options Database Keys: 9925 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9926 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9927 9928 Level: intermediate 9929 9930 Notes: 9931 Orthogonal quality is given by the following formula\: 9932 9933 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9934 9935 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 9936 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9937 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9938 calculating the cosine of the angle between these vectors. 9939 9940 Orthogonal quality ranges from 1 (best) to 0 (worst). 9941 9942 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9943 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9944 9945 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9946 9947 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9948 @*/ 9949 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9950 { 9951 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9952 PetscInt *idx; 9953 PetscScalar *oqVals; 9954 const PetscScalar *cellGeomArr, *faceGeomArr; 9955 PetscReal *ci, *fi, *Ai; 9956 MPI_Comm comm; 9957 Vec cellgeom, facegeom; 9958 DM dmFace, dmCell; 9959 IS glob; 9960 ISLocalToGlobalMapping ltog; 9961 PetscViewer vwr; 9962 9963 PetscFunctionBegin; 9964 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9965 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9966 PetscAssertPointer(OrthQual, 4); 9967 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9968 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9969 PetscCall(DMGetDimension(dm, &nc)); 9970 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9971 { 9972 DMPlexInterpolatedFlag interpFlag; 9973 9974 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9975 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9976 PetscMPIInt rank; 9977 9978 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9979 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9980 } 9981 } 9982 if (OrthQualLabel) { 9983 PetscAssertPointer(OrthQualLabel, 5); 9984 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9985 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9986 } else { 9987 *OrthQualLabel = NULL; 9988 } 9989 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9990 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9991 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9992 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9993 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9994 PetscCall(VecCreate(comm, OrthQual)); 9995 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9996 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9997 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9998 PetscCall(VecSetUp(*OrthQual)); 9999 PetscCall(ISDestroy(&glob)); 10000 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 10001 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 10002 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 10003 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 10004 PetscCall(VecGetDM(cellgeom, &dmCell)); 10005 PetscCall(VecGetDM(facegeom, &dmFace)); 10006 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 10007 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 10008 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 10009 PetscInt cellarr[2], *adj = NULL; 10010 PetscScalar *cArr, *fArr; 10011 PetscReal minvalc = 1.0, minvalf = 1.0; 10012 PetscFVCellGeom *cg; 10013 10014 idx[cellIter] = cell - cStart; 10015 cellarr[0] = cell; 10016 /* Make indexing into cellGeom easier */ 10017 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10018 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10019 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10020 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10021 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10022 PetscInt i; 10023 const PetscInt neigh = adj[cellneigh]; 10024 PetscReal normci = 0, normfi = 0, normai = 0; 10025 PetscFVCellGeom *cgneigh; 10026 PetscFVFaceGeom *fg; 10027 10028 /* Don't count ourselves in the neighbor list */ 10029 if (neigh == cell) continue; 10030 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10031 cellarr[1] = neigh; 10032 { 10033 PetscInt numcovpts; 10034 const PetscInt *covpts; 10035 10036 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10037 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10038 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10039 } 10040 10041 /* Compute c_i, f_i and their norms */ 10042 for (i = 0; i < nc; i++) { 10043 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10044 fi[i] = fg->centroid[i] - cg->centroid[i]; 10045 Ai[i] = fg->normal[i]; 10046 normci += PetscPowReal(ci[i], 2); 10047 normfi += PetscPowReal(fi[i], 2); 10048 normai += PetscPowReal(Ai[i], 2); 10049 } 10050 normci = PetscSqrtReal(normci); 10051 normfi = PetscSqrtReal(normfi); 10052 normai = PetscSqrtReal(normai); 10053 10054 /* Normalize and compute for each face-cell-normal pair */ 10055 for (i = 0; i < nc; i++) { 10056 ci[i] = ci[i] / normci; 10057 fi[i] = fi[i] / normfi; 10058 Ai[i] = Ai[i] / normai; 10059 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10060 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10061 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10062 } 10063 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10064 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10065 } 10066 PetscCall(PetscFree(adj)); 10067 PetscCall(PetscFree2(cArr, fArr)); 10068 /* Defer to cell if they're equal */ 10069 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10070 if (OrthQualLabel) { 10071 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10072 } 10073 } 10074 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10075 PetscCall(VecAssemblyBegin(*OrthQual)); 10076 PetscCall(VecAssemblyEnd(*OrthQual)); 10077 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10078 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10079 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10080 if (OrthQualLabel) { 10081 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10082 } 10083 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10084 PetscCall(PetscViewerDestroy(&vwr)); 10085 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10086 PetscFunctionReturn(PETSC_SUCCESS); 10087 } 10088 10089 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10090 * interpolator construction */ 10091 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10092 { 10093 PetscSection section, newSection, gsection; 10094 PetscSF sf; 10095 PetscBool hasConstraints, ghasConstraints; 10096 10097 PetscFunctionBegin; 10098 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10099 PetscAssertPointer(odm, 2); 10100 PetscCall(DMGetLocalSection(dm, §ion)); 10101 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10102 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10103 if (!ghasConstraints) { 10104 PetscCall(PetscObjectReference((PetscObject)dm)); 10105 *odm = dm; 10106 PetscFunctionReturn(PETSC_SUCCESS); 10107 } 10108 PetscCall(DMClone(dm, odm)); 10109 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10110 PetscCall(DMGetLocalSection(*odm, &newSection)); 10111 PetscCall(DMGetPointSF(*odm, &sf)); 10112 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10113 PetscCall(DMSetGlobalSection(*odm, gsection)); 10114 PetscCall(PetscSectionDestroy(&gsection)); 10115 PetscFunctionReturn(PETSC_SUCCESS); 10116 } 10117 10118 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10119 { 10120 DM dmco, dmfo; 10121 Mat interpo; 10122 Vec rscale; 10123 Vec cglobalo, clocal; 10124 Vec fglobal, fglobalo, flocal; 10125 PetscBool regular; 10126 10127 PetscFunctionBegin; 10128 PetscCall(DMGetFullDM(dmc, &dmco)); 10129 PetscCall(DMGetFullDM(dmf, &dmfo)); 10130 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10131 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10132 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10133 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10134 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10135 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10136 PetscCall(VecSet(cglobalo, 0.)); 10137 PetscCall(VecSet(clocal, 0.)); 10138 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10139 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10140 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10141 PetscCall(VecSet(fglobal, 0.)); 10142 PetscCall(VecSet(fglobalo, 0.)); 10143 PetscCall(VecSet(flocal, 0.)); 10144 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10145 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10146 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10147 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10148 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10149 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10150 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10151 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10152 *shift = fglobal; 10153 PetscCall(VecDestroy(&flocal)); 10154 PetscCall(VecDestroy(&fglobalo)); 10155 PetscCall(VecDestroy(&clocal)); 10156 PetscCall(VecDestroy(&cglobalo)); 10157 PetscCall(VecDestroy(&rscale)); 10158 PetscCall(MatDestroy(&interpo)); 10159 PetscCall(DMDestroy(&dmfo)); 10160 PetscCall(DMDestroy(&dmco)); 10161 PetscFunctionReturn(PETSC_SUCCESS); 10162 } 10163 10164 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10165 { 10166 PetscObject shifto; 10167 Vec shift; 10168 10169 PetscFunctionBegin; 10170 if (!interp) { 10171 Vec rscale; 10172 10173 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10174 PetscCall(VecDestroy(&rscale)); 10175 } else { 10176 PetscCall(PetscObjectReference((PetscObject)interp)); 10177 } 10178 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10179 if (!shifto) { 10180 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10181 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10182 shifto = (PetscObject)shift; 10183 PetscCall(VecDestroy(&shift)); 10184 } 10185 shift = (Vec)shifto; 10186 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10187 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10188 PetscCall(MatDestroy(&interp)); 10189 PetscFunctionReturn(PETSC_SUCCESS); 10190 } 10191 10192 /* Pointwise interpolation 10193 Just code FEM for now 10194 u^f = I u^c 10195 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10196 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10197 I_{ij} = psi^f_i phi^c_j 10198 */ 10199 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10200 { 10201 PetscSection gsc, gsf; 10202 PetscInt m, n; 10203 void *ctx; 10204 DM cdm; 10205 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10206 10207 PetscFunctionBegin; 10208 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10209 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10210 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10211 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10212 10213 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10214 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10215 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10216 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10217 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10218 10219 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10220 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10221 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10222 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10223 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10224 if (scaling) { 10225 /* Use naive scaling */ 10226 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10227 } 10228 PetscFunctionReturn(PETSC_SUCCESS); 10229 } 10230 10231 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10232 { 10233 VecScatter ctx; 10234 10235 PetscFunctionBegin; 10236 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10237 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10238 PetscCall(VecScatterDestroy(&ctx)); 10239 PetscFunctionReturn(PETSC_SUCCESS); 10240 } 10241 10242 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[]) 10243 { 10244 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10245 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10246 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10247 } 10248 10249 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10250 { 10251 DM dmc; 10252 PetscDS ds; 10253 Vec ones, locmass; 10254 IS cellIS; 10255 PetscFormKey key; 10256 PetscInt depth; 10257 10258 PetscFunctionBegin; 10259 PetscCall(DMClone(dm, &dmc)); 10260 PetscCall(DMCopyDisc(dm, dmc)); 10261 PetscCall(DMGetDS(dmc, &ds)); 10262 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10263 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10264 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10265 else PetscCall(DMGetLocalVector(dm, &locmass)); 10266 PetscCall(DMGetLocalVector(dm, &ones)); 10267 PetscCall(DMPlexGetDepth(dm, &depth)); 10268 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10269 PetscCall(VecSet(locmass, 0.0)); 10270 PetscCall(VecSet(ones, 1.0)); 10271 key.label = NULL; 10272 key.value = 0; 10273 key.field = 0; 10274 key.part = 0; 10275 PetscCall(DMPlexComputeJacobianActionByKey(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10276 PetscCall(ISDestroy(&cellIS)); 10277 if (mass) { 10278 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10279 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10280 } 10281 PetscCall(DMRestoreLocalVector(dm, &ones)); 10282 if (lmass) *lmass = locmass; 10283 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10284 PetscCall(DMDestroy(&dmc)); 10285 PetscFunctionReturn(PETSC_SUCCESS); 10286 } 10287 10288 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10289 { 10290 PetscSection gsc, gsf; 10291 PetscInt m, n; 10292 void *ctx; 10293 DM cdm; 10294 PetscBool regular; 10295 10296 PetscFunctionBegin; 10297 if (dmFine == dmCoarse) { 10298 DM dmc; 10299 PetscDS ds; 10300 PetscWeakForm wf; 10301 Vec u; 10302 IS cellIS; 10303 PetscFormKey key; 10304 PetscInt depth; 10305 10306 PetscCall(DMClone(dmFine, &dmc)); 10307 PetscCall(DMCopyDisc(dmFine, dmc)); 10308 PetscCall(DMGetDS(dmc, &ds)); 10309 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10310 PetscCall(PetscWeakFormClear(wf)); 10311 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10312 PetscCall(DMCreateMatrix(dmc, mass)); 10313 PetscCall(DMGetLocalVector(dmc, &u)); 10314 PetscCall(DMPlexGetDepth(dmc, &depth)); 10315 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10316 PetscCall(MatZeroEntries(*mass)); 10317 key.label = NULL; 10318 key.value = 0; 10319 key.field = 0; 10320 key.part = 0; 10321 PetscCall(DMPlexComputeJacobianByKey(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10322 PetscCall(ISDestroy(&cellIS)); 10323 PetscCall(DMRestoreLocalVector(dmc, &u)); 10324 PetscCall(DMDestroy(&dmc)); 10325 } else { 10326 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10327 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10328 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10329 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10330 10331 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10332 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10333 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10334 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10335 10336 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10337 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10338 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10339 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10340 } 10341 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10342 PetscFunctionReturn(PETSC_SUCCESS); 10343 } 10344 10345 /*@ 10346 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10347 10348 Input Parameter: 10349 . dm - The `DMPLEX` object 10350 10351 Output Parameter: 10352 . regular - The flag 10353 10354 Level: intermediate 10355 10356 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10357 @*/ 10358 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10359 { 10360 PetscFunctionBegin; 10361 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10362 PetscAssertPointer(regular, 2); 10363 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10364 PetscFunctionReturn(PETSC_SUCCESS); 10365 } 10366 10367 /*@ 10368 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10369 10370 Input Parameters: 10371 + dm - The `DMPLEX` object 10372 - regular - The flag 10373 10374 Level: intermediate 10375 10376 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10377 @*/ 10378 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10379 { 10380 PetscFunctionBegin; 10381 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10382 ((DM_Plex *)dm->data)->regularRefinement = regular; 10383 PetscFunctionReturn(PETSC_SUCCESS); 10384 } 10385 10386 /*@ 10387 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10388 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10389 10390 Not Collective 10391 10392 Input Parameter: 10393 . dm - The `DMPLEX` object 10394 10395 Output Parameters: 10396 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10397 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10398 10399 Level: intermediate 10400 10401 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10402 @*/ 10403 PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS) 10404 { 10405 DM_Plex *plex = (DM_Plex *)dm->data; 10406 10407 PetscFunctionBegin; 10408 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10409 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10410 if (anchorSection) *anchorSection = plex->anchorSection; 10411 if (anchorIS) *anchorIS = plex->anchorIS; 10412 PetscFunctionReturn(PETSC_SUCCESS); 10413 } 10414 10415 /*@ 10416 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10417 10418 Collective 10419 10420 Input Parameters: 10421 + dm - The `DMPLEX` object 10422 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10423 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10424 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10425 10426 Level: intermediate 10427 10428 Notes: 10429 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10430 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10431 combination of other points' degrees of freedom. 10432 10433 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10434 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10435 10436 The reference counts of `anchorSection` and `anchorIS` are incremented. 10437 10438 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10439 @*/ 10440 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10441 { 10442 DM_Plex *plex = (DM_Plex *)dm->data; 10443 PetscMPIInt result; 10444 10445 PetscFunctionBegin; 10446 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10447 if (anchorSection) { 10448 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10449 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10450 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10451 } 10452 if (anchorIS) { 10453 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10454 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10455 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10456 } 10457 10458 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10459 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10460 plex->anchorSection = anchorSection; 10461 10462 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10463 PetscCall(ISDestroy(&plex->anchorIS)); 10464 plex->anchorIS = anchorIS; 10465 10466 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10467 PetscInt size, a, pStart, pEnd; 10468 const PetscInt *anchors; 10469 10470 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10471 PetscCall(ISGetLocalSize(anchorIS, &size)); 10472 PetscCall(ISGetIndices(anchorIS, &anchors)); 10473 for (a = 0; a < size; a++) { 10474 PetscInt p; 10475 10476 p = anchors[a]; 10477 if (p >= pStart && p < pEnd) { 10478 PetscInt dof; 10479 10480 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10481 if (dof) { 10482 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10483 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10484 } 10485 } 10486 } 10487 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10488 } 10489 /* reset the generic constraints */ 10490 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10491 PetscFunctionReturn(PETSC_SUCCESS); 10492 } 10493 10494 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10495 { 10496 PetscSection anchorSection; 10497 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10498 10499 PetscFunctionBegin; 10500 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10501 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10502 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10503 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10504 if (numFields) { 10505 PetscInt f; 10506 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10507 10508 for (f = 0; f < numFields; f++) { 10509 PetscInt numComp; 10510 10511 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10512 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10513 } 10514 } 10515 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10516 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10517 pStart = PetscMax(pStart, sStart); 10518 pEnd = PetscMin(pEnd, sEnd); 10519 pEnd = PetscMax(pStart, pEnd); 10520 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10521 for (p = pStart; p < pEnd; p++) { 10522 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10523 if (dof) { 10524 PetscCall(PetscSectionGetDof(section, p, &dof)); 10525 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10526 for (f = 0; f < numFields; f++) { 10527 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10528 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10529 } 10530 } 10531 } 10532 PetscCall(PetscSectionSetUp(*cSec)); 10533 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10534 PetscFunctionReturn(PETSC_SUCCESS); 10535 } 10536 10537 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10538 { 10539 PetscSection aSec; 10540 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10541 const PetscInt *anchors; 10542 PetscInt numFields, f; 10543 IS aIS; 10544 MatType mtype; 10545 PetscBool iscuda, iskokkos; 10546 10547 PetscFunctionBegin; 10548 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10549 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10550 PetscCall(PetscSectionGetStorageSize(section, &n)); 10551 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10552 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10553 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10554 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10555 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10556 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10557 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10558 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10559 else mtype = MATSEQAIJ; 10560 PetscCall(MatSetType(*cMat, mtype)); 10561 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10562 PetscCall(ISGetIndices(aIS, &anchors)); 10563 /* cSec will be a subset of aSec and section */ 10564 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10565 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10566 PetscCall(PetscMalloc1(m + 1, &i)); 10567 i[0] = 0; 10568 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10569 for (p = pStart; p < pEnd; p++) { 10570 PetscInt rDof, rOff, r; 10571 10572 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10573 if (!rDof) continue; 10574 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10575 if (numFields) { 10576 for (f = 0; f < numFields; f++) { 10577 annz = 0; 10578 for (r = 0; r < rDof; r++) { 10579 a = anchors[rOff + r]; 10580 if (a < sStart || a >= sEnd) continue; 10581 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10582 annz += aDof; 10583 } 10584 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10585 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10586 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10587 } 10588 } else { 10589 annz = 0; 10590 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10591 for (q = 0; q < dof; q++) { 10592 a = anchors[rOff + q]; 10593 if (a < sStart || a >= sEnd) continue; 10594 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10595 annz += aDof; 10596 } 10597 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10598 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10599 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10600 } 10601 } 10602 nnz = i[m]; 10603 PetscCall(PetscMalloc1(nnz, &j)); 10604 offset = 0; 10605 for (p = pStart; p < pEnd; p++) { 10606 if (numFields) { 10607 for (f = 0; f < numFields; f++) { 10608 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10609 for (q = 0; q < dof; q++) { 10610 PetscInt rDof, rOff, r; 10611 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10612 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10613 for (r = 0; r < rDof; r++) { 10614 PetscInt s; 10615 10616 a = anchors[rOff + r]; 10617 if (a < sStart || a >= sEnd) continue; 10618 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10619 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10620 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10621 } 10622 } 10623 } 10624 } else { 10625 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10626 for (q = 0; q < dof; q++) { 10627 PetscInt rDof, rOff, r; 10628 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10629 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10630 for (r = 0; r < rDof; r++) { 10631 PetscInt s; 10632 10633 a = anchors[rOff + r]; 10634 if (a < sStart || a >= sEnd) continue; 10635 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10636 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10637 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10638 } 10639 } 10640 } 10641 } 10642 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10643 PetscCall(PetscFree(i)); 10644 PetscCall(PetscFree(j)); 10645 PetscCall(ISRestoreIndices(aIS, &anchors)); 10646 PetscFunctionReturn(PETSC_SUCCESS); 10647 } 10648 10649 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10650 { 10651 DM_Plex *plex = (DM_Plex *)dm->data; 10652 PetscSection anchorSection, section, cSec; 10653 Mat cMat; 10654 10655 PetscFunctionBegin; 10656 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10657 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10658 if (anchorSection) { 10659 PetscInt Nf; 10660 10661 PetscCall(DMGetLocalSection(dm, §ion)); 10662 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10663 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10664 PetscCall(DMGetNumFields(dm, &Nf)); 10665 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10666 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10667 PetscCall(PetscSectionDestroy(&cSec)); 10668 PetscCall(MatDestroy(&cMat)); 10669 } 10670 PetscFunctionReturn(PETSC_SUCCESS); 10671 } 10672 10673 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10674 { 10675 IS subis; 10676 PetscSection section, subsection; 10677 10678 PetscFunctionBegin; 10679 PetscCall(DMGetLocalSection(dm, §ion)); 10680 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10681 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10682 /* Create subdomain */ 10683 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10684 /* Create submodel */ 10685 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10686 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10687 PetscCall(DMSetLocalSection(*subdm, subsection)); 10688 PetscCall(PetscSectionDestroy(&subsection)); 10689 PetscCall(DMCopyDisc(dm, *subdm)); 10690 /* Create map from submodel to global model */ 10691 if (is) { 10692 PetscSection sectionGlobal, subsectionGlobal; 10693 IS spIS; 10694 const PetscInt *spmap; 10695 PetscInt *subIndices; 10696 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10697 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10698 10699 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10700 PetscCall(ISGetIndices(spIS, &spmap)); 10701 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10702 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10703 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10704 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10705 for (p = pStart; p < pEnd; ++p) { 10706 PetscInt gdof, pSubSize = 0; 10707 10708 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10709 if (gdof > 0) { 10710 for (f = 0; f < Nf; ++f) { 10711 PetscInt fdof, fcdof; 10712 10713 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10714 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10715 pSubSize += fdof - fcdof; 10716 } 10717 subSize += pSubSize; 10718 if (pSubSize) { 10719 if (bs < 0) { 10720 bs = pSubSize; 10721 } else if (bs != pSubSize) { 10722 /* Layout does not admit a pointwise block size */ 10723 bs = 1; 10724 } 10725 } 10726 } 10727 } 10728 /* Must have same blocksize on all procs (some might have no points) */ 10729 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10730 bsLocal[1] = bs; 10731 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10732 if (bsMinMax[0] != bsMinMax[1]) { 10733 bs = 1; 10734 } else { 10735 bs = bsMinMax[0]; 10736 } 10737 PetscCall(PetscMalloc1(subSize, &subIndices)); 10738 for (p = pStart; p < pEnd; ++p) { 10739 PetscInt gdof, goff; 10740 10741 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10742 if (gdof > 0) { 10743 const PetscInt point = spmap[p]; 10744 10745 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10746 for (f = 0; f < Nf; ++f) { 10747 PetscInt fdof, fcdof, fc, f2, poff = 0; 10748 10749 /* Can get rid of this loop by storing field information in the global section */ 10750 for (f2 = 0; f2 < f; ++f2) { 10751 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10752 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10753 poff += fdof - fcdof; 10754 } 10755 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10756 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10757 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10758 } 10759 } 10760 } 10761 PetscCall(ISRestoreIndices(spIS, &spmap)); 10762 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10763 if (bs > 1) { 10764 /* We need to check that the block size does not come from non-contiguous fields */ 10765 PetscInt i, j, set = 1; 10766 for (i = 0; i < subSize; i += bs) { 10767 for (j = 0; j < bs; ++j) { 10768 if (subIndices[i + j] != subIndices[i] + j) { 10769 set = 0; 10770 break; 10771 } 10772 } 10773 } 10774 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10775 } 10776 /* Attach nullspace */ 10777 for (f = 0; f < Nf; ++f) { 10778 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10779 if ((*subdm)->nullspaceConstructors[f]) break; 10780 } 10781 if (f < Nf) { 10782 MatNullSpace nullSpace; 10783 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10784 10785 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10786 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10787 } 10788 } 10789 PetscFunctionReturn(PETSC_SUCCESS); 10790 } 10791 10792 /*@ 10793 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10794 10795 Input Parameters: 10796 + dm - The `DM` 10797 - dummy - unused argument 10798 10799 Options Database Key: 10800 . -dm_plex_monitor_throughput - Activate the monitor 10801 10802 Level: developer 10803 10804 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10805 @*/ 10806 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10807 { 10808 PetscLogHandler default_handler; 10809 10810 PetscFunctionBegin; 10811 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10812 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10813 if (default_handler) { 10814 PetscLogEvent event; 10815 PetscEventPerfInfo eventInfo; 10816 PetscLogDouble cellRate, flopRate; 10817 PetscInt cStart, cEnd, Nf, N; 10818 const char *name; 10819 10820 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10821 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10822 PetscCall(DMGetNumFields(dm, &Nf)); 10823 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10824 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10825 N = (cEnd - cStart) * Nf * eventInfo.count; 10826 flopRate = eventInfo.flops / eventInfo.time; 10827 cellRate = N / eventInfo.time; 10828 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)); 10829 } else { 10830 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."); 10831 } 10832 PetscFunctionReturn(PETSC_SUCCESS); 10833 } 10834