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