1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_CreateBoxSFC, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 /* Logging support */ 18 PetscLogEvent DMPLEX_DistributionView, DMPLEX_DistributionLoad; 19 20 PetscBool Plexcite = PETSC_FALSE; 21 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 22 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 23 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 24 "journal = {SIAM Journal on Scientific Computing},\n" 25 "volume = {38},\n" 26 "number = {5},\n" 27 "pages = {S143--S155},\n" 28 "eprint = {http://arxiv.org/abs/1506.07749},\n" 29 "doi = {10.1137/15M1026092},\n" 30 "year = {2016},\n" 31 "petsc_uses={DMPlex},\n}\n"; 32 33 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 34 35 /*@ 36 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 37 38 Input Parameter: 39 . dm - The `DMPLEX` object 40 41 Output Parameter: 42 . simplex - Flag checking for a simplex 43 44 Level: intermediate 45 46 Note: 47 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 48 If the mesh has no cells, this returns `PETSC_FALSE`. 49 50 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 51 @*/ 52 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 53 { 54 DMPolytopeType ct; 55 PetscInt cStart, cEnd; 56 57 PetscFunctionBegin; 58 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 59 if (cEnd <= cStart) { 60 *simplex = PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 64 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 65 PetscFunctionReturn(PETSC_SUCCESS); 66 } 67 68 /*@ 69 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 70 71 Input Parameters: 72 + dm - The `DMPLEX` object 73 - height - The cell height in the Plex, 0 is the default 74 75 Output Parameters: 76 + cStart - The first "normal" cell, pass `NULL` if not needed 77 - cEnd - The upper bound on "normal" cells, pass `NULL` if not needed 78 79 Level: developer 80 81 Note: 82 This function requires that tensor cells are ordered last. 83 84 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 85 @*/ 86 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PeOp PetscInt *cStart, PeOp PetscInt *cEnd) 87 { 88 DMLabel ctLabel; 89 IS valueIS; 90 const PetscInt *ctypes; 91 PetscBool found = PETSC_FALSE; 92 PetscInt Nct, cS = PETSC_INT_MAX, cE = 0; 93 94 PetscFunctionBegin; 95 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 96 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 97 PetscCall(ISGetLocalSize(valueIS, &Nct)); 98 PetscCall(ISGetIndices(valueIS, &ctypes)); 99 for (PetscInt t = 0; t < Nct; ++t) { 100 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 101 PetscInt ctS, ctE, ht; 102 103 if (ct == DM_POLYTOPE_UNKNOWN) { 104 // If any cells are not typed, just use all cells 105 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 106 break; 107 } 108 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 109 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 110 if (ctS >= ctE) continue; 111 // Check that a point has the right height 112 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 113 if (ht != height) continue; 114 cS = PetscMin(cS, ctS); 115 cE = PetscMax(cE, ctE); 116 found = PETSC_TRUE; 117 } 118 if (!Nct || !found) cS = cE = 0; 119 PetscCall(ISDestroy(&valueIS)); 120 // Reset label for fast lookup 121 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 122 if (cStart) *cStart = cS; 123 if (cEnd) *cEnd = cE; 124 PetscFunctionReturn(PETSC_SUCCESS); 125 } 126 127 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 128 { 129 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 130 PetscInt *sStart, *sEnd; 131 PetscViewerVTKFieldType *ft; 132 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 133 DMLabel depthLabel, ctLabel; 134 135 PetscFunctionBegin; 136 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 137 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 138 PetscCall(DMGetCoordinateDim(dm, &cdim)); 139 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 140 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 141 if (field >= 0) { 142 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 143 } else { 144 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 145 } 146 147 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 148 PetscCall(DMPlexGetDepth(dm, &depth)); 149 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 150 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 151 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 152 const DMPolytopeType ict = (DMPolytopeType)c; 153 PetscInt dep; 154 155 if (ict == DM_POLYTOPE_FV_GHOST) continue; 156 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 157 if (pStart >= 0) { 158 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 159 if (dep != depth - cellHeight) continue; 160 } 161 if (field >= 0) { 162 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 163 } else { 164 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 165 } 166 } 167 168 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 169 *types = 0; 170 171 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 172 if (globalvcdof[c]) ++(*types); 173 } 174 175 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 176 t = 0; 177 if (globalvcdof[DM_NUM_POLYTOPES]) { 178 sStart[t] = vStart; 179 sEnd[t] = vEnd; 180 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 181 ++t; 182 } 183 184 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 185 if (globalvcdof[c]) { 186 const DMPolytopeType ict = (DMPolytopeType)c; 187 188 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 189 sStart[t] = cStart; 190 sEnd[t] = cEnd; 191 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 192 ++t; 193 } 194 } 195 196 if (!*types) { 197 if (field >= 0) { 198 const char *fieldname; 199 200 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 201 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 202 } else { 203 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 204 } 205 } 206 207 *ssStart = sStart; 208 *ssEnd = sEnd; 209 *sft = ft; 210 PetscFunctionReturn(PETSC_SUCCESS); 211 } 212 213 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 214 { 215 PetscFunctionBegin; 216 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 217 PetscFunctionReturn(PETSC_SUCCESS); 218 } 219 220 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 221 { 222 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 223 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 224 225 PetscFunctionBegin; 226 *ft = PETSC_VTK_INVALID; 227 PetscCall(DMGetCoordinateDim(dm, &cdim)); 228 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 229 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 230 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 231 if (field >= 0) { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 234 } else { 235 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 236 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 237 } 238 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 239 if (globalvcdof[0]) { 240 *sStart = vStart; 241 *sEnd = vEnd; 242 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 243 else *ft = PETSC_VTK_POINT_FIELD; 244 } else if (globalvcdof[1]) { 245 *sStart = cStart; 246 *sEnd = cEnd; 247 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 248 else *ft = PETSC_VTK_CELL_FIELD; 249 } else { 250 if (field >= 0) { 251 const char *fieldname; 252 253 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 254 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 255 } else { 256 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n")); 257 } 258 } 259 PetscFunctionReturn(PETSC_SUCCESS); 260 } 261 262 /*@ 263 DMPlexVecView1D - Plot many 1D solutions on the same line graph 264 265 Collective 266 267 Input Parameters: 268 + dm - The `DMPLEX` object 269 . n - The number of vectors 270 . u - The array of local vectors 271 - viewer - The `PetscViewer` 272 273 Level: advanced 274 275 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 276 @*/ 277 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 278 { 279 DM cdm; 280 PetscDS ds; 281 PetscDraw draw = NULL; 282 PetscDrawLG lg; 283 Vec coordinates; 284 const PetscScalar *coords, **sol; 285 PetscReal *vals; 286 PetscInt *Nc; 287 PetscInt Nf, Nl, vStart, vEnd, eStart, eEnd; 288 char **names; 289 290 PetscFunctionBegin; 291 PetscCall(DMGetCoordinateDM(dm, &cdm)); 292 PetscCall(DMGetDS(dm, &ds)); 293 PetscCall(PetscDSGetNumFields(ds, &Nf)); 294 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 295 PetscCall(PetscDSGetComponents(ds, &Nc)); 296 297 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 298 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 299 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 300 301 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 302 for (PetscInt i = 0, l = 0; i < n; ++i) { 303 const char *vname; 304 305 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 306 for (PetscInt f = 0; f < Nf; ++f) { 307 PetscObject disc; 308 const char *fname; 309 char tmpname[PETSC_MAX_PATH_LEN]; 310 311 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 312 /* TODO Create names for components */ 313 for (PetscInt c = 0; c < Nc[f]; ++c, ++l) { 314 PetscCall(PetscObjectGetName(disc, &fname)); 315 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 316 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 317 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 318 PetscCall(PetscStrallocpy(tmpname, &names[l])); 319 } 320 } 321 } 322 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 323 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 324 PetscCall(VecGetArrayRead(coordinates, &coords)); 325 for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 326 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 327 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 328 PetscSection s; 329 PetscInt cdof, vdof; 330 331 PetscCall(DMGetLocalSection(dm, &s)); 332 PetscCall(PetscSectionGetDof(s, eStart, &cdof)); 333 PetscCall(PetscSectionGetDof(s, vStart, &vdof)); 334 if (cdof) { 335 if (vdof) { 336 // P_2 337 PetscInt vFirst = -1; 338 339 for (PetscInt e = eStart; e < eEnd; ++e) { 340 PetscScalar *xa, *xb, *svals; 341 const PetscInt *cone; 342 343 PetscCall(DMPlexGetCone(dm, e, &cone)); 344 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 345 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 346 if (e == eStart) vFirst = cone[0]; 347 for (PetscInt i = 0; i < n; ++i) { 348 PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals)); 349 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 350 } 351 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals)); 352 if (e == eEnd - 1 && cone[1] != vFirst) { 353 for (PetscInt i = 0; i < n; ++i) { 354 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 355 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 356 } 357 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 358 for (PetscInt i = 0; i < n; ++i) { 359 PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals)); 360 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 361 } 362 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals)); 363 } 364 } 365 } else { 366 // P_0 367 for (PetscInt e = eStart; e < eEnd; ++e) { 368 PetscScalar *xa, *xb, *svals; 369 const PetscInt *cone; 370 371 PetscCall(DMPlexGetCone(dm, e, &cone)); 372 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 373 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 374 for (PetscInt i = 0; i < n; ++i) { 375 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 376 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 377 } 378 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 379 } 380 } 381 } else if (vdof) { 382 // P_1 383 for (PetscInt v = vStart; v < vEnd; ++v) { 384 PetscScalar *x, *svals; 385 386 PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x)); 387 for (PetscInt i = 0; i < n; ++i) { 388 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 389 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 390 } 391 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 392 } 393 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Discretization not supported"); 394 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 395 for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 396 for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 397 PetscCall(PetscFree3(sol, names, vals)); 398 399 PetscCall(PetscDrawLGDraw(lg)); 400 PetscCall(PetscDrawLGDestroy(&lg)); 401 PetscFunctionReturn(PETSC_SUCCESS); 402 } 403 404 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 405 { 406 DM dm; 407 408 PetscFunctionBegin; 409 PetscCall(VecGetDM(u, &dm)); 410 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 411 PetscFunctionReturn(PETSC_SUCCESS); 412 } 413 414 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 415 { 416 DM dm; 417 PetscSection s; 418 PetscDraw draw, popup; 419 DM cdm; 420 PetscSection coordSection; 421 Vec coordinates; 422 const PetscScalar *array; 423 PetscReal lbound[3], ubound[3]; 424 PetscReal vbound[2], time; 425 PetscBool flg; 426 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 427 const char *name; 428 char title[PETSC_MAX_PATH_LEN]; 429 430 PetscFunctionBegin; 431 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 432 PetscCall(VecGetDM(v, &dm)); 433 PetscCall(DMGetCoordinateDim(dm, &dim)); 434 PetscCall(DMGetLocalSection(dm, &s)); 435 PetscCall(PetscSectionGetNumFields(s, &Nf)); 436 PetscCall(DMGetCoarsenLevel(dm, &level)); 437 PetscCall(DMGetCoordinateDM(dm, &cdm)); 438 PetscCall(DMGetLocalSection(cdm, &coordSection)); 439 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 440 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 441 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 442 443 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 444 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 445 446 PetscCall(VecGetLocalSize(coordinates, &N)); 447 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 448 PetscCall(PetscDrawClear(draw)); 449 450 /* Could implement something like DMDASelectFields() */ 451 for (f = 0; f < Nf; ++f) { 452 DM fdm = dm; 453 Vec fv = v; 454 IS fis; 455 char prefix[PETSC_MAX_PATH_LEN]; 456 const char *fname; 457 458 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 459 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 460 461 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 462 else prefix[0] = '\0'; 463 if (Nf > 1) { 464 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 465 PetscCall(VecGetSubVector(v, fis, &fv)); 466 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 467 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 468 } 469 for (comp = 0; comp < Nc; ++comp, ++w) { 470 PetscInt nmax = 2; 471 472 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 473 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 474 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 475 PetscCall(PetscDrawSetTitle(draw, title)); 476 477 /* TODO Get max and min only for this component */ 478 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 479 if (!flg) { 480 PetscCall(VecMin(fv, NULL, &vbound[0])); 481 PetscCall(VecMax(fv, NULL, &vbound[1])); 482 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 483 } 484 485 PetscCall(PetscDrawGetPopup(draw, &popup)); 486 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 487 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 488 PetscCall(VecGetArrayRead(fv, &array)); 489 for (c = cStart; c < cEnd; ++c) { 490 DMPolytopeType ct; 491 PetscScalar *coords = NULL, *a = NULL; 492 const PetscScalar *coords_arr; 493 PetscBool isDG; 494 PetscInt numCoords; 495 int color[4] = {-1, -1, -1, -1}; 496 497 PetscCall(DMPlexGetCellType(dm, c, &ct)); 498 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 499 if (a) { 500 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 501 color[1] = color[2] = color[3] = color[0]; 502 } else { 503 PetscScalar *vals = NULL; 504 PetscInt numVals, va; 505 506 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 507 if (!numVals) { 508 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 509 continue; 510 } 511 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 512 switch (numVals / Nc) { 513 case 1: /* P1 Clamped Segment Prism */ 514 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 515 PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]); 516 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 517 break; 518 case 3: /* P1 Triangle */ 519 case 4: /* P1 Quadrangle */ 520 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 521 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 522 break; 523 case 6: /* P2 Triangle */ 524 case 8: /* P2 Quadrangle */ 525 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 526 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 527 break; 528 default: 529 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 530 } 531 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 532 } 533 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 534 switch (numCoords) { 535 case 6: 536 case 12: /* Localized triangle */ 537 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 538 break; 539 case 8: 540 case 16: /* Localized quadrilateral */ 541 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 542 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 543 } else { 544 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 545 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 546 } 547 break; 548 default: 549 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 550 } 551 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 552 } 553 PetscCall(VecRestoreArrayRead(fv, &array)); 554 PetscCall(PetscDrawFlush(draw)); 555 PetscCall(PetscDrawPause(draw)); 556 PetscCall(PetscDrawSave(draw)); 557 } 558 if (Nf > 1) { 559 PetscCall(VecRestoreSubVector(v, fis, &fv)); 560 PetscCall(ISDestroy(&fis)); 561 PetscCall(DMDestroy(&fdm)); 562 } 563 } 564 PetscFunctionReturn(PETSC_SUCCESS); 565 } 566 567 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 568 { 569 DM dm; 570 PetscDraw draw; 571 PetscInt dim; 572 PetscBool isnull; 573 574 PetscFunctionBegin; 575 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 576 PetscCall(PetscDrawIsNull(draw, &isnull)); 577 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 578 579 PetscCall(VecGetDM(v, &dm)); 580 PetscCall(DMGetCoordinateDim(dm, &dim)); 581 switch (dim) { 582 case 1: 583 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 584 break; 585 case 2: 586 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 587 break; 588 default: 589 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 590 } 591 PetscFunctionReturn(PETSC_SUCCESS); 592 } 593 594 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 595 { 596 DM dm; 597 Vec locv; 598 const char *name; 599 PetscSection section; 600 PetscInt pStart, pEnd; 601 PetscInt numFields; 602 PetscViewerVTKFieldType ft; 603 604 PetscFunctionBegin; 605 PetscCall(VecGetDM(v, &dm)); 606 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 607 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 608 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 609 PetscCall(VecCopy(v, locv)); 610 PetscCall(DMGetLocalSection(dm, §ion)); 611 PetscCall(PetscSectionGetNumFields(section, &numFields)); 612 if (!numFields) { 613 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 614 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 615 } else { 616 PetscInt f; 617 618 for (f = 0; f < numFields; f++) { 619 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 620 if (ft == PETSC_VTK_INVALID) continue; 621 PetscCall(PetscObjectReference((PetscObject)locv)); 622 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 623 } 624 PetscCall(VecDestroy(&locv)); 625 } 626 PetscFunctionReturn(PETSC_SUCCESS); 627 } 628 629 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 630 { 631 DM dm; 632 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython; 633 634 PetscFunctionBegin; 635 PetscCall(VecGetDM(v, &dm)); 636 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 640 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 641 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 642 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 643 if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) { 644 PetscInt i, numFields; 645 PetscObject fe; 646 PetscBool fem = PETSC_FALSE; 647 Vec locv = v; 648 const char *name; 649 PetscInt step; 650 PetscReal time; 651 652 PetscCall(DMGetNumFields(dm, &numFields)); 653 for (i = 0; i < numFields; i++) { 654 PetscCall(DMGetField(dm, i, NULL, &fe)); 655 if (fe->classid == PETSCFE_CLASSID) { 656 fem = PETSC_TRUE; 657 break; 658 } 659 } 660 if (fem) { 661 PetscObject isZero; 662 663 PetscCall(DMGetLocalVector(dm, &locv)); 664 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 665 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 666 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 667 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 668 PetscCall(VecCopy(v, locv)); 669 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 670 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 671 } 672 if (isvtk) { 673 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 674 } else if (ishdf5) { 675 #if defined(PETSC_HAVE_HDF5) 676 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 677 #else 678 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 679 #endif 680 } else if (isdraw) { 681 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 682 } else if (ispython) { 683 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv)); 684 } else if (isglvis) { 685 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 686 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 687 PetscCall(VecView_GLVis(locv, viewer)); 688 } else if (iscgns) { 689 #if defined(PETSC_HAVE_CGNS) 690 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 691 #else 692 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 693 #endif 694 } 695 if (fem) { 696 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 697 PetscCall(DMRestoreLocalVector(dm, &locv)); 698 } 699 } else { 700 PetscBool isseq; 701 702 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 703 if (isseq) PetscCall(VecView_Seq(v, viewer)); 704 else PetscCall(VecView_MPI(v, viewer)); 705 } 706 PetscFunctionReturn(PETSC_SUCCESS); 707 } 708 709 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 710 { 711 DM dm; 712 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython; 713 714 PetscFunctionBegin; 715 PetscCall(VecGetDM(v, &dm)); 716 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 721 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 722 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 723 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 724 if (isvtk || isdraw || isglvis || iscgns || ispython) { 725 Vec locv; 726 PetscObject isZero; 727 const char *name; 728 729 PetscCall(DMGetLocalVector(dm, &locv)); 730 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 731 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 732 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 733 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 734 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 735 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 736 PetscCall(VecView_Plex_Local(locv, viewer)); 737 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 738 PetscCall(DMRestoreLocalVector(dm, &locv)); 739 } else if (ishdf5) { 740 #if defined(PETSC_HAVE_HDF5) 741 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 742 #else 743 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 744 #endif 745 } else if (isexodusii) { 746 #if defined(PETSC_HAVE_EXODUSII) 747 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 748 #else 749 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 750 #endif 751 } else { 752 PetscBool isseq; 753 754 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 755 if (isseq) PetscCall(VecView_Seq(v, viewer)); 756 else PetscCall(VecView_MPI(v, viewer)); 757 } 758 PetscFunctionReturn(PETSC_SUCCESS); 759 } 760 761 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 762 { 763 DM dm; 764 MPI_Comm comm; 765 PetscViewerFormat format; 766 Vec v; 767 PetscBool isvtk, ishdf5; 768 769 PetscFunctionBegin; 770 PetscCall(VecGetDM(originalv, &dm)); 771 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 772 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 773 PetscCall(PetscViewerGetFormat(viewer, &format)); 774 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 775 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 776 if (format == PETSC_VIEWER_NATIVE) { 777 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 778 /* this need a better fix */ 779 if (dm->useNatural) { 780 if (dm->sfNatural) { 781 const char *vecname; 782 PetscInt n, nroots; 783 784 PetscCall(VecGetLocalSize(originalv, &n)); 785 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 786 if (n == nroots) { 787 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 788 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 789 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 790 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 791 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 792 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 793 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 794 } else v = originalv; 795 } else v = originalv; 796 797 if (ishdf5) { 798 #if defined(PETSC_HAVE_HDF5) 799 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 800 #else 801 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 802 #endif 803 } else if (isvtk) { 804 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 805 } else { 806 PetscBool isseq; 807 808 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 809 if (isseq) PetscCall(VecView_Seq(v, viewer)); 810 else PetscCall(VecView_MPI(v, viewer)); 811 } 812 if (v != originalv) PetscCall(VecDestroy(&v)); 813 PetscFunctionReturn(PETSC_SUCCESS); 814 } 815 816 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 817 { 818 DM dm; 819 PetscBool ishdf5; 820 821 PetscFunctionBegin; 822 PetscCall(VecGetDM(v, &dm)); 823 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 824 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 825 if (ishdf5) { 826 DM dmBC; 827 Vec gv; 828 const char *name; 829 830 PetscCall(DMGetOutputDM(dm, &dmBC)); 831 PetscCall(DMGetGlobalVector(dmBC, &gv)); 832 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 833 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 834 PetscCall(VecLoad_Default(gv, viewer)); 835 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 836 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 837 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 838 } else PetscCall(VecLoad_Default(v, viewer)); 839 PetscFunctionReturn(PETSC_SUCCESS); 840 } 841 842 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 843 { 844 DM dm; 845 PetscBool ishdf5, isexodusii, iscgns; 846 847 PetscFunctionBegin; 848 PetscCall(VecGetDM(v, &dm)); 849 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 850 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 851 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 852 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 853 if (ishdf5) { 854 #if defined(PETSC_HAVE_HDF5) 855 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 856 #else 857 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 858 #endif 859 } else if (isexodusii) { 860 #if defined(PETSC_HAVE_EXODUSII) 861 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 862 #else 863 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 864 #endif 865 } else if (iscgns) { 866 #if defined(PETSC_HAVE_CGNS) 867 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 868 #else 869 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 870 #endif 871 } else PetscCall(VecLoad_Default(v, viewer)); 872 PetscFunctionReturn(PETSC_SUCCESS); 873 } 874 875 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 876 { 877 DM dm; 878 PetscViewerFormat format; 879 PetscBool ishdf5; 880 881 PetscFunctionBegin; 882 PetscCall(VecGetDM(originalv, &dm)); 883 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 884 PetscCall(PetscViewerGetFormat(viewer, &format)); 885 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 886 if (format == PETSC_VIEWER_NATIVE) { 887 if (dm->useNatural) { 888 if (dm->sfNatural) { 889 if (ishdf5) { 890 #if defined(PETSC_HAVE_HDF5) 891 Vec v; 892 const char *vecname; 893 894 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 895 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 896 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 897 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 898 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 899 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 900 PetscCall(VecDestroy(&v)); 901 #else 902 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 903 #endif 904 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 905 } 906 } else PetscCall(VecLoad_Default(originalv, viewer)); 907 } 908 PetscFunctionReturn(PETSC_SUCCESS); 909 } 910 911 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 912 { 913 PetscSection coordSection; 914 Vec coordinates; 915 DMLabel depthLabel, celltypeLabel; 916 const char *name[4]; 917 const PetscScalar *a; 918 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 919 920 PetscFunctionBegin; 921 PetscCall(DMGetDimension(dm, &dim)); 922 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 923 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 924 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 925 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 926 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 927 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 928 PetscCall(VecGetArrayRead(coordinates, &a)); 929 name[0] = "vertex"; 930 name[1] = "edge"; 931 name[dim - 1] = "face"; 932 name[dim] = "cell"; 933 for (c = cStart; c < cEnd; ++c) { 934 PetscInt *closure = NULL; 935 PetscInt closureSize, cl, ct; 936 937 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 938 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 939 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 940 PetscCall(PetscViewerASCIIPushTab(viewer)); 941 for (cl = 0; cl < closureSize * 2; cl += 2) { 942 PetscInt point = closure[cl], depth, dof, off, d, p; 943 944 if ((point < pStart) || (point >= pEnd)) continue; 945 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 946 if (!dof) continue; 947 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 948 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 949 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 950 for (p = 0; p < dof / dim; ++p) { 951 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 952 for (d = 0; d < dim; ++d) { 953 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 955 } 956 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 957 } 958 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 959 } 960 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 961 PetscCall(PetscViewerASCIIPopTab(viewer)); 962 } 963 PetscCall(VecRestoreArrayRead(coordinates, &a)); 964 PetscFunctionReturn(PETSC_SUCCESS); 965 } 966 967 typedef enum { 968 CS_CARTESIAN, 969 CS_POLAR, 970 CS_CYLINDRICAL, 971 CS_SPHERICAL 972 } CoordSystem; 973 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 974 975 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 976 { 977 PetscInt i; 978 979 PetscFunctionBegin; 980 if (dim > 3) { 981 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 982 } else { 983 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 984 985 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 986 switch (cs) { 987 case CS_CARTESIAN: 988 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 989 break; 990 case CS_POLAR: 991 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 992 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 993 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 994 break; 995 case CS_CYLINDRICAL: 996 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 997 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 998 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 999 trcoords[2] = coords[2]; 1000 break; 1001 case CS_SPHERICAL: 1002 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 1003 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 1004 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 1005 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 1006 break; 1007 } 1008 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 1009 } 1010 PetscFunctionReturn(PETSC_SUCCESS); 1011 } 1012 1013 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 1014 { 1015 DM_Plex *mesh = (DM_Plex *)dm->data; 1016 DM cdm, cdmCell; 1017 PetscSection coordSection, coordSectionCell; 1018 Vec coordinates, coordinatesCell; 1019 PetscViewerFormat format; 1020 1021 PetscFunctionBegin; 1022 PetscCall(PetscViewerGetFormat(viewer, &format)); 1023 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1024 const char *name; 1025 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1026 PetscInt pStart, pEnd, p, numLabels, l; 1027 PetscMPIInt rank, size; 1028 1029 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1030 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1031 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1032 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1033 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1034 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1035 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1036 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1037 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1038 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1039 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1040 PetscCall(DMGetDimension(dm, &dim)); 1041 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1042 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1043 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1044 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1045 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1046 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1047 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1048 for (p = pStart; p < pEnd; ++p) { 1049 PetscInt dof, off, s; 1050 1051 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1052 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1053 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1054 } 1055 PetscCall(PetscViewerFlush(viewer)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1057 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1058 for (p = pStart; p < pEnd; ++p) { 1059 PetscInt dof, off, c; 1060 1061 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1062 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1063 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 1064 } 1065 PetscCall(PetscViewerFlush(viewer)); 1066 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1067 if (coordSection && coordinates) { 1068 CoordSystem cs = CS_CARTESIAN; 1069 const PetscScalar *array, *arrayCell = NULL; 1070 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1071 PetscMPIInt rank; 1072 const char *name; 1073 1074 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1075 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1076 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1077 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1078 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1079 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1080 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1081 pStart = PetscMin(pvStart, pcStart); 1082 pEnd = PetscMax(pvEnd, pcEnd); 1083 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1084 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1085 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1086 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1087 1088 PetscCall(VecGetArrayRead(coordinates, &array)); 1089 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1090 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1091 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1092 for (p = pStart; p < pEnd; ++p) { 1093 PetscInt dof, off; 1094 1095 if (p >= pvStart && p < pvEnd) { 1096 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1097 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1098 if (dof) { 1099 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1100 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1101 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1102 } 1103 } 1104 if (cdmCell && p >= pcStart && p < pcEnd) { 1105 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1106 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1107 if (dof) { 1108 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1109 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1110 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1111 } 1112 } 1113 } 1114 PetscCall(PetscViewerFlush(viewer)); 1115 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1116 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1117 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1118 } 1119 PetscCall(DMGetNumLabels(dm, &numLabels)); 1120 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1121 for (l = 0; l < numLabels; ++l) { 1122 DMLabel label; 1123 PetscBool isdepth; 1124 const char *name; 1125 1126 PetscCall(DMGetLabelName(dm, l, &name)); 1127 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1128 if (isdepth) continue; 1129 PetscCall(DMGetLabel(dm, name, &label)); 1130 PetscCall(DMLabelView(label, viewer)); 1131 } 1132 if (size > 1) { 1133 PetscSF sf; 1134 1135 PetscCall(DMGetPointSF(dm, &sf)); 1136 PetscCall(PetscSFView(sf, viewer)); 1137 } 1138 if (mesh->periodic.face_sfs) 1139 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1140 PetscCall(PetscViewerFlush(viewer)); 1141 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1142 const char *name, *color; 1143 const char *defcolors[3] = {"gray", "orange", "green"}; 1144 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1145 char lname[PETSC_MAX_PATH_LEN]; 1146 PetscReal scale = 2.0; 1147 PetscReal tikzscale = 1.0; 1148 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1149 double tcoords[3]; 1150 PetscScalar *coords; 1151 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 1152 PetscMPIInt rank, size; 1153 char **names, **colors, **lcolors; 1154 PetscBool flg, lflg; 1155 PetscBT wp = NULL; 1156 PetscInt pEnd, pStart; 1157 1158 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1159 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1160 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1161 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1162 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1163 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1164 PetscCall(DMGetDimension(dm, &dim)); 1165 PetscCall(DMPlexGetDepth(dm, &depth)); 1166 PetscCall(DMGetNumLabels(dm, &numLabels)); 1167 numLabels = PetscMax(numLabels, 10); 1168 numColors = 10; 1169 numLColors = 10; 1170 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1171 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1172 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1173 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1174 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1175 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1176 n = 4; 1177 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1178 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1179 n = 4; 1180 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1181 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1182 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1183 if (!useLabels) numLabels = 0; 1184 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1185 if (!useColors) { 1186 numColors = 3; 1187 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1188 } 1189 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1190 if (!useColors) { 1191 numLColors = 4; 1192 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1193 } 1194 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1195 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1196 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1197 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1198 if (depth < dim) plotEdges = PETSC_FALSE; 1199 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1200 1201 /* filter points with labelvalue != labeldefaultvalue */ 1202 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1203 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1204 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1205 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1206 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1207 if (lflg) { 1208 DMLabel lbl; 1209 1210 PetscCall(DMGetLabel(dm, lname, &lbl)); 1211 if (lbl) { 1212 PetscInt val, defval; 1213 1214 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1215 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1216 for (c = pStart; c < pEnd; c++) { 1217 PetscInt *closure = NULL; 1218 PetscInt closureSize; 1219 1220 PetscCall(DMLabelGetValue(lbl, c, &val)); 1221 if (val == defval) continue; 1222 1223 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1224 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1225 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1226 } 1227 } 1228 } 1229 1230 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1231 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1232 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1234 \\documentclass[tikz]{standalone}\n\n\ 1235 \\usepackage{pgflibraryshapes}\n\ 1236 \\usetikzlibrary{backgrounds}\n\ 1237 \\usetikzlibrary{arrows}\n\ 1238 \\begin{document}\n")); 1239 if (size > 1) { 1240 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1241 for (p = 0; p < size; ++p) { 1242 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1243 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1244 } 1245 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1246 } 1247 if (drawHasse) { 1248 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1249 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1258 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1264 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1265 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1266 } 1267 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1268 1269 /* Plot vertices */ 1270 PetscCall(VecGetArray(coordinates, &coords)); 1271 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1272 for (v = vStart; v < vEnd; ++v) { 1273 PetscInt off, dof, d; 1274 PetscBool isLabeled = PETSC_FALSE; 1275 1276 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1277 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1278 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1280 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1281 for (d = 0; d < dof; ++d) { 1282 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1283 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1284 } 1285 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1286 if (dim == 3) { 1287 PetscReal tmp = tcoords[1]; 1288 tcoords[1] = tcoords[2]; 1289 tcoords[2] = -tmp; 1290 } 1291 for (d = 0; d < dof; ++d) { 1292 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1293 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1294 } 1295 if (drawHasse) color = colors[0 % numColors]; 1296 else color = colors[rank % numColors]; 1297 for (l = 0; l < numLabels; ++l) { 1298 PetscInt val; 1299 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1300 if (val >= 0) { 1301 color = lcolors[l % numLColors]; 1302 isLabeled = PETSC_TRUE; 1303 break; 1304 } 1305 } 1306 if (drawNumbers[0]) { 1307 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1308 } else if (drawColors[0]) { 1309 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1310 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1311 } 1312 PetscCall(VecRestoreArray(coordinates, &coords)); 1313 PetscCall(PetscViewerFlush(viewer)); 1314 /* Plot edges */ 1315 if (plotEdges) { 1316 PetscCall(VecGetArray(coordinates, &coords)); 1317 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1318 for (e = eStart; e < eEnd; ++e) { 1319 const PetscInt *cone; 1320 PetscInt coneSize, offA, offB, dof, d; 1321 1322 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1323 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1324 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1325 PetscCall(DMPlexGetCone(dm, e, &cone)); 1326 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1327 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1328 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1329 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1330 for (d = 0; d < dof; ++d) { 1331 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1332 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1333 } 1334 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1335 if (dim == 3) { 1336 PetscReal tmp = tcoords[1]; 1337 tcoords[1] = tcoords[2]; 1338 tcoords[2] = -tmp; 1339 } 1340 for (d = 0; d < dof; ++d) { 1341 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1342 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1343 } 1344 if (drawHasse) color = colors[1 % numColors]; 1345 else color = colors[rank % numColors]; 1346 for (l = 0; l < numLabels; ++l) { 1347 PetscInt val; 1348 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1349 if (val >= 0) { 1350 color = lcolors[l % numLColors]; 1351 break; 1352 } 1353 } 1354 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1355 } 1356 PetscCall(VecRestoreArray(coordinates, &coords)); 1357 PetscCall(PetscViewerFlush(viewer)); 1358 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1359 } 1360 /* Plot cells */ 1361 if (dim == 3 || !drawNumbers[1]) { 1362 for (e = eStart; e < eEnd; ++e) { 1363 const PetscInt *cone; 1364 1365 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1366 color = colors[rank % numColors]; 1367 for (l = 0; l < numLabels; ++l) { 1368 PetscInt val; 1369 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1370 if (val >= 0) { 1371 color = lcolors[l % numLColors]; 1372 break; 1373 } 1374 } 1375 PetscCall(DMPlexGetCone(dm, e, &cone)); 1376 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1377 } 1378 } else { 1379 DMPolytopeType ct; 1380 1381 /* Drawing a 2D polygon */ 1382 for (c = cStart; c < cEnd; ++c) { 1383 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1384 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1385 if (DMPolytopeTypeIsHybrid(ct)) { 1386 const PetscInt *cone; 1387 PetscInt coneSize, e; 1388 1389 PetscCall(DMPlexGetCone(dm, c, &cone)); 1390 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1391 for (e = 0; e < coneSize; ++e) { 1392 const PetscInt *econe; 1393 1394 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1395 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1396 } 1397 } else { 1398 PetscInt *closure = NULL; 1399 PetscInt closureSize, Nv = 0, v; 1400 1401 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1402 for (p = 0; p < closureSize * 2; p += 2) { 1403 const PetscInt point = closure[p]; 1404 1405 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1406 } 1407 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1408 for (v = 0; v <= Nv; ++v) { 1409 const PetscInt vertex = closure[v % Nv]; 1410 1411 if (v > 0) { 1412 if (plotEdges) { 1413 const PetscInt *edge; 1414 PetscInt endpoints[2], ne; 1415 1416 endpoints[0] = closure[v - 1]; 1417 endpoints[1] = vertex; 1418 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1419 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1420 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1421 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1422 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1423 } 1424 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1425 } 1426 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1427 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1428 } 1429 } 1430 } 1431 for (c = cStart; c < cEnd; ++c) { 1432 double ccoords[3] = {0.0, 0.0, 0.0}; 1433 PetscBool isLabeled = PETSC_FALSE; 1434 PetscScalar *cellCoords = NULL; 1435 const PetscScalar *array; 1436 PetscInt numCoords, cdim, d; 1437 PetscBool isDG; 1438 1439 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1440 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1441 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1442 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1443 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1444 for (p = 0; p < numCoords / cdim; ++p) { 1445 for (d = 0; d < cdim; ++d) { 1446 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1447 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1448 } 1449 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1450 if (cdim == 3) { 1451 PetscReal tmp = tcoords[1]; 1452 tcoords[1] = tcoords[2]; 1453 tcoords[2] = -tmp; 1454 } 1455 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1456 } 1457 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1458 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1459 for (d = 0; d < cdim; ++d) { 1460 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1461 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1462 } 1463 if (drawHasse) color = colors[depth % numColors]; 1464 else color = colors[rank % numColors]; 1465 for (l = 0; l < numLabels; ++l) { 1466 PetscInt val; 1467 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1468 if (val >= 0) { 1469 color = lcolors[l % numLColors]; 1470 isLabeled = PETSC_TRUE; 1471 break; 1472 } 1473 } 1474 if (drawNumbers[dim]) { 1475 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1476 } else if (drawColors[dim]) { 1477 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1478 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1479 } 1480 if (drawHasse) { 1481 int height = 0; 1482 1483 color = colors[depth % numColors]; 1484 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1485 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1486 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1487 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1489 1490 if (depth > 2) { 1491 color = colors[1 % numColors]; 1492 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1493 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1494 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1495 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1496 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1497 } 1498 1499 color = colors[1 % numColors]; 1500 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1502 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1503 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1504 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1505 1506 color = colors[0 % numColors]; 1507 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1510 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1511 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1512 1513 for (p = pStart; p < pEnd; ++p) { 1514 const PetscInt *cone; 1515 PetscInt coneSize, cp; 1516 1517 PetscCall(DMPlexGetCone(dm, p, &cone)); 1518 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1519 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1520 } 1521 } 1522 PetscCall(PetscViewerFlush(viewer)); 1523 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1524 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1525 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1526 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1527 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1528 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1529 PetscCall(PetscFree3(names, colors, lcolors)); 1530 PetscCall(PetscBTDestroy(&wp)); 1531 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1532 Vec cown, acown; 1533 VecScatter sct; 1534 ISLocalToGlobalMapping g2l; 1535 IS gid, acis; 1536 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1537 MPI_Group ggroup, ngroup; 1538 PetscScalar *array, nid; 1539 const PetscInt *idxs; 1540 PetscInt *idxs2, *start, *adjacency, *work; 1541 PetscInt64 lm[3], gm[3]; 1542 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1543 PetscMPIInt d1, d2, rank; 1544 1545 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1546 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1547 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1548 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1549 #endif 1550 if (ncomm != MPI_COMM_NULL) { 1551 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1552 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1553 d1 = 0; 1554 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1555 nid = d2; 1556 PetscCallMPI(MPI_Group_free(&ggroup)); 1557 PetscCallMPI(MPI_Group_free(&ngroup)); 1558 PetscCallMPI(MPI_Comm_free(&ncomm)); 1559 } else nid = 0.0; 1560 1561 /* Get connectivity */ 1562 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1563 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1564 1565 /* filter overlapped local cells */ 1566 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1567 PetscCall(ISGetIndices(gid, &idxs)); 1568 PetscCall(ISGetLocalSize(gid, &cum)); 1569 PetscCall(PetscMalloc1(cum, &idxs2)); 1570 for (c = cStart, cum = 0; c < cEnd; c++) { 1571 if (idxs[c - cStart] < 0) continue; 1572 idxs2[cum++] = idxs[c - cStart]; 1573 } 1574 PetscCall(ISRestoreIndices(gid, &idxs)); 1575 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1576 PetscCall(ISDestroy(&gid)); 1577 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1578 1579 /* support for node-aware cell locality */ 1580 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1581 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1582 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1583 PetscCall(VecGetArray(cown, &array)); 1584 for (c = 0; c < numVertices; c++) array[c] = nid; 1585 PetscCall(VecRestoreArray(cown, &array)); 1586 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1587 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1588 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1589 PetscCall(ISDestroy(&acis)); 1590 PetscCall(VecScatterDestroy(&sct)); 1591 PetscCall(VecDestroy(&cown)); 1592 1593 /* compute edgeCut */ 1594 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1595 PetscCall(PetscMalloc1(cum, &work)); 1596 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1597 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1598 PetscCall(ISDestroy(&gid)); 1599 PetscCall(VecGetArray(acown, &array)); 1600 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1601 PetscInt totl; 1602 1603 totl = start[c + 1] - start[c]; 1604 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1605 for (i = 0; i < totl; i++) { 1606 if (work[i] < 0) { 1607 ect += 1; 1608 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1609 } 1610 } 1611 } 1612 PetscCall(PetscFree(work)); 1613 PetscCall(VecRestoreArray(acown, &array)); 1614 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1615 lm[1] = -numVertices; 1616 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1617 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1618 lm[0] = ect; /* edgeCut */ 1619 lm[1] = ectn; /* node-aware edgeCut */ 1620 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1621 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1622 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1623 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1624 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1625 #else 1626 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1627 #endif 1628 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1629 PetscCall(PetscFree(start)); 1630 PetscCall(PetscFree(adjacency)); 1631 PetscCall(VecDestroy(&acown)); 1632 } else { 1633 const char *name; 1634 PetscInt *sizes, *hybsizes, *ghostsizes; 1635 PetscInt locDepth, depth, cellHeight, dim, d; 1636 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1637 PetscInt numLabels, l, maxSize = 17; 1638 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1639 MPI_Comm comm; 1640 PetscMPIInt size, rank; 1641 1642 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1643 PetscCallMPI(MPI_Comm_size(comm, &size)); 1644 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1645 PetscCall(DMGetDimension(dm, &dim)); 1646 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1647 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1648 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1649 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1650 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1651 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1652 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1653 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1654 gcNum = gcEnd - gcStart; 1655 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1656 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1657 for (d = 0; d <= depth; d++) { 1658 PetscInt Nc[2] = {0, 0}, ict; 1659 1660 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1661 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1662 ict = ct0; 1663 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1664 ct0 = (DMPolytopeType)ict; 1665 for (p = pStart; p < pEnd; ++p) { 1666 DMPolytopeType ct; 1667 1668 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1669 if (ct == ct0) ++Nc[0]; 1670 else ++Nc[1]; 1671 } 1672 if (size < maxSize) { 1673 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1674 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1675 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1676 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1677 for (p = 0; p < size; ++p) { 1678 if (rank == 0) { 1679 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1680 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1681 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1682 } 1683 } 1684 } else { 1685 PetscInt locMinMax[2]; 1686 1687 locMinMax[0] = Nc[0] + Nc[1]; 1688 locMinMax[1] = Nc[0] + Nc[1]; 1689 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1690 locMinMax[0] = Nc[1]; 1691 locMinMax[1] = Nc[1]; 1692 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1693 if (d == depth) { 1694 locMinMax[0] = gcNum; 1695 locMinMax[1] = gcNum; 1696 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1697 } 1698 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1699 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1700 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1701 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1702 } 1703 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1704 } 1705 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1706 { 1707 const PetscReal *maxCell; 1708 const PetscReal *L; 1709 PetscBool localized; 1710 1711 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1712 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1713 if (L || localized) { 1714 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1715 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1716 if (L) { 1717 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1718 for (d = 0; d < dim; ++d) { 1719 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1720 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1721 } 1722 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1723 } 1724 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1725 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1726 } 1727 } 1728 PetscCall(DMGetNumLabels(dm, &numLabels)); 1729 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1730 for (l = 0; l < numLabels; ++l) { 1731 DMLabel label; 1732 const char *name; 1733 PetscInt *values; 1734 PetscInt numValues, v; 1735 1736 PetscCall(DMGetLabelName(dm, l, &name)); 1737 PetscCall(DMGetLabel(dm, name, &label)); 1738 PetscCall(DMLabelGetNumValues(label, &numValues)); 1739 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1740 1741 { // Extract array of DMLabel values so it can be sorted 1742 IS is_values; 1743 const PetscInt *is_values_local = NULL; 1744 1745 PetscCall(DMLabelGetValueIS(label, &is_values)); 1746 PetscCall(ISGetIndices(is_values, &is_values_local)); 1747 PetscCall(PetscMalloc1(numValues, &values)); 1748 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1749 PetscCall(PetscSortInt(numValues, values)); 1750 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1751 PetscCall(ISDestroy(&is_values)); 1752 } 1753 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1754 for (v = 0; v < numValues; ++v) { 1755 PetscInt size; 1756 1757 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1758 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1759 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1760 } 1761 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1762 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1763 PetscCall(PetscFree(values)); 1764 } 1765 { 1766 char **labelNames; 1767 PetscInt Nl = numLabels; 1768 PetscBool flg; 1769 1770 PetscCall(PetscMalloc1(Nl, &labelNames)); 1771 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1772 for (l = 0; l < Nl; ++l) { 1773 DMLabel label; 1774 1775 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1776 if (flg) { 1777 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1778 PetscCall(DMLabelView(label, viewer)); 1779 } 1780 PetscCall(PetscFree(labelNames[l])); 1781 } 1782 PetscCall(PetscFree(labelNames)); 1783 } 1784 /* If no fields are specified, people do not want to see adjacency */ 1785 if (dm->Nf) { 1786 PetscInt f; 1787 1788 for (f = 0; f < dm->Nf; ++f) { 1789 const char *name; 1790 1791 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1792 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1793 PetscCall(PetscViewerASCIIPushTab(viewer)); 1794 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1795 if (dm->fields[f].adjacency[0]) { 1796 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1797 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1798 } else { 1799 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1800 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1801 } 1802 PetscCall(PetscViewerASCIIPopTab(viewer)); 1803 } 1804 } 1805 DMPlexTransform tr; 1806 1807 PetscCall(DMPlexGetTransform(dm, &tr)); 1808 if (tr) { 1809 PetscCall(PetscViewerASCIIPushTab(viewer)); 1810 PetscCall(PetscViewerASCIIPrintf(viewer, "Created using transform:\n")); 1811 PetscCall(DMPlexTransformView(tr, viewer)); 1812 PetscCall(PetscViewerASCIIPopTab(viewer)); 1813 } 1814 PetscCall(DMGetCoarseDM(dm, &cdm)); 1815 if (cdm) { 1816 PetscCall(PetscViewerASCIIPushTab(viewer)); 1817 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1818 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1819 PetscCall(PetscViewerASCIIPopTab(viewer)); 1820 } 1821 } 1822 PetscFunctionReturn(PETSC_SUCCESS); 1823 } 1824 1825 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt 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, NULL)); 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 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5676 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5677 for (PetscInt p = pStart; p < pEnd; p++) { 5678 PetscCall(DMLabelGetValue(label, p, &ct)); 5679 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5680 } 5681 } 5682 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5683 if (PetscDefined(USE_DEBUG)) { 5684 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5685 PetscCall(DMLabelGetValue(label, cell, &ct)); 5686 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5687 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5688 } 5689 } 5690 PetscFunctionReturn(PETSC_SUCCESS); 5691 } 5692 5693 /*@ 5694 DMPlexSetCellType - Set the polytope type of a given cell 5695 5696 Not Collective 5697 5698 Input Parameters: 5699 + dm - The `DMPLEX` object 5700 . cell - The cell 5701 - celltype - The polytope type of the cell 5702 5703 Level: advanced 5704 5705 Note: 5706 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5707 is executed. This function will override the computed type. However, if automatic classification will not succeed 5708 and a user wants to manually specify all types, the classification must be disabled by calling 5709 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5710 5711 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5712 @*/ 5713 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5714 { 5715 DM_Plex *mesh = (DM_Plex *)dm->data; 5716 DMLabel label; 5717 PetscInt pStart, pEnd; 5718 5719 PetscFunctionBegin; 5720 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5721 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5722 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5723 PetscCall(DMLabelSetValue(label, cell, celltype)); 5724 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5725 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5726 PetscFunctionReturn(PETSC_SUCCESS); 5727 } 5728 5729 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5730 { 5731 PetscSection section; 5732 PetscInt maxHeight; 5733 const char *prefix; 5734 5735 PetscFunctionBegin; 5736 PetscCall(DMClone(dm, cdm)); 5737 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5738 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5739 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5740 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5741 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5742 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5743 PetscCall(DMSetLocalSection(*cdm, section)); 5744 PetscCall(PetscSectionDestroy(§ion)); 5745 5746 PetscCall(DMSetNumFields(*cdm, 1)); 5747 PetscCall(DMCreateDS(*cdm)); 5748 (*cdm)->cloneOpts = PETSC_TRUE; 5749 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5750 PetscFunctionReturn(PETSC_SUCCESS); 5751 } 5752 5753 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5754 { 5755 Vec coordsLocal, cellCoordsLocal; 5756 DM coordsDM, cellCoordsDM; 5757 5758 PetscFunctionBegin; 5759 *field = NULL; 5760 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5761 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5762 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5763 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5764 if (coordsLocal && coordsDM) { 5765 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5766 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5767 } 5768 PetscFunctionReturn(PETSC_SUCCESS); 5769 } 5770 5771 /*@ 5772 DMPlexGetConeSection - Return a section which describes the layout of cone data 5773 5774 Not Collective 5775 5776 Input Parameter: 5777 . dm - The `DMPLEX` object 5778 5779 Output Parameter: 5780 . section - The `PetscSection` object 5781 5782 Level: developer 5783 5784 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5785 @*/ 5786 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5787 { 5788 DM_Plex *mesh = (DM_Plex *)dm->data; 5789 5790 PetscFunctionBegin; 5791 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5792 if (section) *section = mesh->coneSection; 5793 PetscFunctionReturn(PETSC_SUCCESS); 5794 } 5795 5796 /*@ 5797 DMPlexGetSupportSection - Return a section which describes the layout of support data 5798 5799 Not Collective 5800 5801 Input Parameter: 5802 . dm - The `DMPLEX` object 5803 5804 Output Parameter: 5805 . section - The `PetscSection` object 5806 5807 Level: developer 5808 5809 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5810 @*/ 5811 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5812 { 5813 DM_Plex *mesh = (DM_Plex *)dm->data; 5814 5815 PetscFunctionBegin; 5816 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5817 if (section) *section = mesh->supportSection; 5818 PetscFunctionReturn(PETSC_SUCCESS); 5819 } 5820 5821 /*@C 5822 DMPlexGetCones - Return cone data 5823 5824 Not Collective 5825 5826 Input Parameter: 5827 . dm - The `DMPLEX` object 5828 5829 Output Parameter: 5830 . cones - The cone for each point 5831 5832 Level: developer 5833 5834 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5835 @*/ 5836 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5837 { 5838 DM_Plex *mesh = (DM_Plex *)dm->data; 5839 5840 PetscFunctionBegin; 5841 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5842 if (cones) *cones = mesh->cones; 5843 PetscFunctionReturn(PETSC_SUCCESS); 5844 } 5845 5846 /*@C 5847 DMPlexGetConeOrientations - Return cone orientation data 5848 5849 Not Collective 5850 5851 Input Parameter: 5852 . dm - The `DMPLEX` object 5853 5854 Output Parameter: 5855 . coneOrientations - The array of cone orientations for all points 5856 5857 Level: developer 5858 5859 Notes: 5860 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5861 as returned by `DMPlexGetConeOrientation()`. 5862 5863 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5864 5865 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5866 @*/ 5867 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5868 { 5869 DM_Plex *mesh = (DM_Plex *)dm->data; 5870 5871 PetscFunctionBegin; 5872 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5873 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5874 PetscFunctionReturn(PETSC_SUCCESS); 5875 } 5876 5877 /* FEM Support */ 5878 5879 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5880 { 5881 PetscInt depth; 5882 5883 PetscFunctionBegin; 5884 PetscCall(DMPlexGetDepth(plex, &depth)); 5885 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5886 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5887 PetscFunctionReturn(PETSC_SUCCESS); 5888 } 5889 5890 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5891 { 5892 PetscInt depth; 5893 5894 PetscFunctionBegin; 5895 PetscCall(DMPlexGetDepth(plex, &depth)); 5896 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5897 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5898 PetscFunctionReturn(PETSC_SUCCESS); 5899 } 5900 5901 /* 5902 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5903 representing a line in the section. 5904 */ 5905 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5906 { 5907 PetscObject obj; 5908 PetscClassId id; 5909 PetscFE fe = NULL; 5910 5911 PetscFunctionBeginHot; 5912 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5913 PetscCall(DMGetField(dm, field, NULL, &obj)); 5914 PetscCall(PetscObjectGetClassId(obj, &id)); 5915 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5916 5917 if (!fe) { 5918 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5919 /* An order k SEM disc has k-1 dofs on an edge */ 5920 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5921 *k = *k / *Nc + 1; 5922 } else { 5923 PetscInt dual_space_size, dim; 5924 PetscDualSpace dsp; 5925 5926 PetscCall(DMGetDimension(dm, &dim)); 5927 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5928 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5929 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5930 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5931 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5932 } 5933 PetscFunctionReturn(PETSC_SUCCESS); 5934 } 5935 5936 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5937 { 5938 PetscFunctionBeginHot; 5939 if (tensor) { 5940 *dof = PetscPowInt(k + 1, dim); 5941 } else { 5942 switch (dim) { 5943 case 1: 5944 *dof = k + 1; 5945 break; 5946 case 2: 5947 *dof = ((k + 1) * (k + 2)) / 2; 5948 break; 5949 case 3: 5950 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5951 break; 5952 default: 5953 *dof = 0; 5954 } 5955 } 5956 PetscFunctionReturn(PETSC_SUCCESS); 5957 } 5958 5959 /*@ 5960 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5961 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5962 section provided (or the section of the `DM`). 5963 5964 Input Parameters: 5965 + dm - The `DM` 5966 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5967 - section - The `PetscSection` to reorder, or `NULL` for the default section 5968 5969 Example: 5970 A typical interpolated single-quad mesh might order points as 5971 .vb 5972 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5973 5974 v4 -- e6 -- v3 5975 | | 5976 e7 c0 e8 5977 | | 5978 v1 -- e5 -- v2 5979 .ve 5980 5981 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5982 dofs in the order of points, e.g., 5983 .vb 5984 c0 -> [0,1,2,3] 5985 v1 -> [4] 5986 ... 5987 e5 -> [8, 9] 5988 .ve 5989 5990 which corresponds to the dofs 5991 .vb 5992 6 10 11 7 5993 13 2 3 15 5994 12 0 1 14 5995 4 8 9 5 5996 .ve 5997 5998 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5999 .vb 6000 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 6001 .ve 6002 6003 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 6004 .vb 6005 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 6006 .ve 6007 6008 Level: developer 6009 6010 Notes: 6011 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 6012 degree of the basis. 6013 6014 This is required to run with libCEED. 6015 6016 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 6017 @*/ 6018 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 6019 { 6020 DMLabel label; 6021 PetscInt dim, depth = -1, eStart = -1, Nf; 6022 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 6023 6024 PetscFunctionBegin; 6025 PetscCall(DMGetDimension(dm, &dim)); 6026 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 6027 if (point < 0) { 6028 PetscInt sStart, sEnd; 6029 6030 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6031 point = sEnd - sStart ? sStart : point; 6032 } 6033 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6034 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6035 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6036 if (depth == 1) { 6037 eStart = point; 6038 } else if (depth == dim) { 6039 const PetscInt *cone; 6040 6041 PetscCall(DMPlexGetCone(dm, point, &cone)); 6042 if (dim == 2) eStart = cone[0]; 6043 else if (dim == 3) { 6044 const PetscInt *cone2; 6045 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6046 eStart = cone2[0]; 6047 } 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); 6048 } 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); 6049 6050 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6051 for (PetscInt d = 1; d <= dim; d++) { 6052 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6053 PetscInt *perm; 6054 6055 for (f = 0; f < Nf; ++f) { 6056 PetscInt dof; 6057 6058 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6059 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6060 if (!continuous && d < dim) continue; 6061 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6062 size += dof * Nc; 6063 } 6064 PetscCall(PetscMalloc1(size, &perm)); 6065 for (f = 0; f < Nf; ++f) { 6066 switch (d) { 6067 case 1: 6068 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6069 if (!continuous && d < dim) continue; 6070 /* 6071 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6072 We want [ vtx0; edge of length k-1; vtx1 ] 6073 */ 6074 if (continuous) { 6075 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6076 for (i = 0; i < k - 1; i++) 6077 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6078 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6079 foffset = offset; 6080 } else { 6081 PetscInt dof; 6082 6083 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6084 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6085 foffset = offset; 6086 } 6087 break; 6088 case 2: 6089 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6090 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6091 if (!continuous && d < dim) continue; 6092 /* The SEM order is 6093 6094 v_lb, {e_b}, v_rb, 6095 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6096 v_lt, reverse {e_t}, v_rt 6097 */ 6098 if (continuous) { 6099 const PetscInt of = 0; 6100 const PetscInt oeb = of + PetscSqr(k - 1); 6101 const PetscInt oer = oeb + (k - 1); 6102 const PetscInt oet = oer + (k - 1); 6103 const PetscInt oel = oet + (k - 1); 6104 const PetscInt ovlb = oel + (k - 1); 6105 const PetscInt ovrb = ovlb + 1; 6106 const PetscInt ovrt = ovrb + 1; 6107 const PetscInt ovlt = ovrt + 1; 6108 PetscInt o; 6109 6110 /* bottom */ 6111 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6112 for (o = oeb; o < oer; ++o) 6113 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6114 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6115 /* middle */ 6116 for (i = 0; i < k - 1; ++i) { 6117 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6118 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6119 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6120 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6121 } 6122 /* top */ 6123 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6124 for (o = oel - 1; o >= oet; --o) 6125 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6126 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6127 foffset = offset; 6128 } else { 6129 PetscInt dof; 6130 6131 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6132 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6133 foffset = offset; 6134 } 6135 break; 6136 case 3: 6137 /* The original hex closure is 6138 6139 {c, 6140 f_b, f_t, f_f, f_b, f_r, f_l, 6141 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6142 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6143 */ 6144 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6145 if (!continuous && d < dim) continue; 6146 /* The SEM order is 6147 Bottom Slice 6148 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6149 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6150 v_blb, {e_bb}, v_brb, 6151 6152 Middle Slice (j) 6153 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6154 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6155 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6156 6157 Top Slice 6158 v_tlf, {e_tf}, v_trf, 6159 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6160 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6161 */ 6162 if (continuous) { 6163 const PetscInt oc = 0; 6164 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6165 const PetscInt oft = ofb + PetscSqr(k - 1); 6166 const PetscInt off = oft + PetscSqr(k - 1); 6167 const PetscInt ofk = off + PetscSqr(k - 1); 6168 const PetscInt ofr = ofk + PetscSqr(k - 1); 6169 const PetscInt ofl = ofr + PetscSqr(k - 1); 6170 const PetscInt oebl = ofl + PetscSqr(k - 1); 6171 const PetscInt oebb = oebl + (k - 1); 6172 const PetscInt oebr = oebb + (k - 1); 6173 const PetscInt oebf = oebr + (k - 1); 6174 const PetscInt oetf = oebf + (k - 1); 6175 const PetscInt oetr = oetf + (k - 1); 6176 const PetscInt oetb = oetr + (k - 1); 6177 const PetscInt oetl = oetb + (k - 1); 6178 const PetscInt oerf = oetl + (k - 1); 6179 const PetscInt oelf = oerf + (k - 1); 6180 const PetscInt oelb = oelf + (k - 1); 6181 const PetscInt oerb = oelb + (k - 1); 6182 const PetscInt ovblf = oerb + (k - 1); 6183 const PetscInt ovblb = ovblf + 1; 6184 const PetscInt ovbrb = ovblb + 1; 6185 const PetscInt ovbrf = ovbrb + 1; 6186 const PetscInt ovtlf = ovbrf + 1; 6187 const PetscInt ovtrf = ovtlf + 1; 6188 const PetscInt ovtrb = ovtrf + 1; 6189 const PetscInt ovtlb = ovtrb + 1; 6190 PetscInt o, n; 6191 6192 /* Bottom Slice */ 6193 /* bottom */ 6194 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6195 for (o = oetf - 1; o >= oebf; --o) 6196 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6197 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6198 /* middle */ 6199 for (i = 0; i < k - 1; ++i) { 6200 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6201 for (n = 0; n < k - 1; ++n) { 6202 o = ofb + n * (k - 1) + i; 6203 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6204 } 6205 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6206 } 6207 /* top */ 6208 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6209 for (o = oebb; o < oebr; ++o) 6210 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6211 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6212 6213 /* Middle Slice */ 6214 for (j = 0; j < k - 1; ++j) { 6215 /* bottom */ 6216 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6217 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6218 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6219 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6220 /* middle */ 6221 for (i = 0; i < k - 1; ++i) { 6222 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6223 for (n = 0; n < k - 1; ++n) 6224 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6225 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6226 } 6227 /* top */ 6228 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6229 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6230 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6231 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6232 } 6233 6234 /* Top Slice */ 6235 /* bottom */ 6236 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6237 for (o = oetf; o < oetr; ++o) 6238 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6239 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6240 /* middle */ 6241 for (i = 0; i < k - 1; ++i) { 6242 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6243 for (n = 0; n < k - 1; ++n) 6244 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6245 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6246 } 6247 /* top */ 6248 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6249 for (o = oetl - 1; o >= oetb; --o) 6250 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6251 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6252 6253 foffset = offset; 6254 } else { 6255 PetscInt dof; 6256 6257 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6258 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6259 foffset = offset; 6260 } 6261 break; 6262 default: 6263 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6264 } 6265 } 6266 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6267 /* Check permutation */ 6268 { 6269 PetscInt *check; 6270 6271 PetscCall(PetscMalloc1(size, &check)); 6272 for (i = 0; i < size; ++i) { 6273 check[i] = -1; 6274 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6275 } 6276 for (i = 0; i < size; ++i) check[perm[i]] = i; 6277 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6278 PetscCall(PetscFree(check)); 6279 } 6280 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6281 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6282 PetscInt *loc_perm; 6283 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6284 for (PetscInt i = 0; i < size; i++) { 6285 loc_perm[i] = perm[i]; 6286 loc_perm[size + i] = size + perm[i]; 6287 } 6288 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6289 } 6290 } 6291 PetscFunctionReturn(PETSC_SUCCESS); 6292 } 6293 6294 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6295 { 6296 PetscDS prob; 6297 PetscInt depth, Nf, h; 6298 DMLabel label; 6299 6300 PetscFunctionBeginHot; 6301 PetscCall(DMGetDS(dm, &prob)); 6302 Nf = prob->Nf; 6303 label = dm->depthLabel; 6304 *dspace = NULL; 6305 if (field < Nf) { 6306 PetscObject disc = prob->disc[field]; 6307 6308 if (disc->classid == PETSCFE_CLASSID) { 6309 PetscDualSpace dsp; 6310 6311 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6312 PetscCall(DMLabelGetNumValues(label, &depth)); 6313 PetscCall(DMLabelGetValue(label, point, &h)); 6314 h = depth - 1 - h; 6315 if (h) { 6316 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6317 } else { 6318 *dspace = dsp; 6319 } 6320 } 6321 } 6322 PetscFunctionReturn(PETSC_SUCCESS); 6323 } 6324 6325 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6326 { 6327 PetscScalar *array; 6328 const PetscScalar *vArray; 6329 const PetscInt *cone, *coneO; 6330 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6331 6332 PetscFunctionBeginHot; 6333 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6334 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6335 PetscCall(DMPlexGetCone(dm, point, &cone)); 6336 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6337 if (!values || !*values) { 6338 if ((point >= pStart) && (point < pEnd)) { 6339 PetscInt dof; 6340 6341 PetscCall(PetscSectionGetDof(section, point, &dof)); 6342 size += dof; 6343 } 6344 for (p = 0; p < numPoints; ++p) { 6345 const PetscInt cp = cone[p]; 6346 PetscInt dof; 6347 6348 if ((cp < pStart) || (cp >= pEnd)) continue; 6349 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6350 size += dof; 6351 } 6352 if (!values) { 6353 if (csize) *csize = size; 6354 PetscFunctionReturn(PETSC_SUCCESS); 6355 } 6356 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6357 } else { 6358 array = *values; 6359 } 6360 size = 0; 6361 PetscCall(VecGetArrayRead(v, &vArray)); 6362 if ((point >= pStart) && (point < pEnd)) { 6363 PetscInt dof, off, d; 6364 const PetscScalar *varr; 6365 6366 PetscCall(PetscSectionGetDof(section, point, &dof)); 6367 PetscCall(PetscSectionGetOffset(section, point, &off)); 6368 varr = PetscSafePointerPlusOffset(vArray, off); 6369 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6370 size += dof; 6371 } 6372 for (p = 0; p < numPoints; ++p) { 6373 const PetscInt cp = cone[p]; 6374 PetscInt o = coneO[p]; 6375 PetscInt dof, off, d; 6376 const PetscScalar *varr; 6377 6378 if ((cp < pStart) || (cp >= pEnd)) continue; 6379 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6380 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6381 varr = PetscSafePointerPlusOffset(vArray, off); 6382 if (o >= 0) { 6383 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6384 } else { 6385 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6386 } 6387 size += dof; 6388 } 6389 PetscCall(VecRestoreArrayRead(v, &vArray)); 6390 if (!*values) { 6391 if (csize) *csize = size; 6392 *values = array; 6393 } else { 6394 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6395 *csize = size; 6396 } 6397 PetscFunctionReturn(PETSC_SUCCESS); 6398 } 6399 6400 /* Compress out points not in the section */ 6401 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6402 { 6403 const PetscInt np = *numPoints; 6404 PetscInt pStart, pEnd, p, q; 6405 6406 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6407 for (p = 0, q = 0; p < np; ++p) { 6408 const PetscInt r = points[p * 2]; 6409 if ((r >= pStart) && (r < pEnd)) { 6410 points[q * 2] = r; 6411 points[q * 2 + 1] = points[p * 2 + 1]; 6412 ++q; 6413 } 6414 } 6415 *numPoints = q; 6416 return PETSC_SUCCESS; 6417 } 6418 6419 /* Compressed closure does not apply closure permutation */ 6420 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6421 { 6422 const PetscInt *cla = NULL; 6423 PetscInt np, *pts = NULL; 6424 6425 PetscFunctionBeginHot; 6426 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6427 if (!ornt && *clPoints) { 6428 PetscInt dof, off; 6429 6430 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6431 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6432 PetscCall(ISGetIndices(*clPoints, &cla)); 6433 np = dof / 2; 6434 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6435 } else { 6436 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6437 PetscCall(CompressPoints_Private(section, &np, pts)); 6438 } 6439 *numPoints = np; 6440 *points = pts; 6441 *clp = cla; 6442 PetscFunctionReturn(PETSC_SUCCESS); 6443 } 6444 6445 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6446 { 6447 PetscFunctionBeginHot; 6448 if (!*clPoints) { 6449 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6450 } else { 6451 PetscCall(ISRestoreIndices(*clPoints, clp)); 6452 } 6453 *numPoints = 0; 6454 *points = NULL; 6455 *clSec = NULL; 6456 *clPoints = NULL; 6457 *clp = NULL; 6458 PetscFunctionReturn(PETSC_SUCCESS); 6459 } 6460 6461 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6462 { 6463 PetscInt offset = 0, p; 6464 const PetscInt **perms = NULL; 6465 const PetscScalar **flips = NULL; 6466 6467 PetscFunctionBeginHot; 6468 *size = 0; 6469 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6470 for (p = 0; p < numPoints; p++) { 6471 const PetscInt point = points[2 * p]; 6472 const PetscInt *perm = perms ? perms[p] : NULL; 6473 const PetscScalar *flip = flips ? flips[p] : NULL; 6474 PetscInt dof, off, d; 6475 const PetscScalar *varr; 6476 6477 PetscCall(PetscSectionGetDof(section, point, &dof)); 6478 PetscCall(PetscSectionGetOffset(section, point, &off)); 6479 varr = PetscSafePointerPlusOffset(vArray, off); 6480 if (clperm) { 6481 if (perm) { 6482 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6483 } else { 6484 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6485 } 6486 if (flip) { 6487 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6488 } 6489 } else { 6490 if (perm) { 6491 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6492 } else { 6493 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6494 } 6495 if (flip) { 6496 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6497 } 6498 } 6499 offset += dof; 6500 } 6501 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6502 *size = offset; 6503 PetscFunctionReturn(PETSC_SUCCESS); 6504 } 6505 6506 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[]) 6507 { 6508 PetscInt offset = 0, f; 6509 6510 PetscFunctionBeginHot; 6511 *size = 0; 6512 for (f = 0; f < numFields; ++f) { 6513 PetscInt p; 6514 const PetscInt **perms = NULL; 6515 const PetscScalar **flips = NULL; 6516 6517 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6518 for (p = 0; p < numPoints; p++) { 6519 const PetscInt point = points[2 * p]; 6520 PetscInt fdof, foff, b; 6521 const PetscScalar *varr; 6522 const PetscInt *perm = perms ? perms[p] : NULL; 6523 const PetscScalar *flip = flips ? flips[p] : NULL; 6524 6525 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6526 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6527 varr = &vArray[foff]; 6528 if (clperm) { 6529 if (perm) { 6530 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6531 } else { 6532 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6533 } 6534 if (flip) { 6535 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6536 } 6537 } else { 6538 if (perm) { 6539 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6540 } else { 6541 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6542 } 6543 if (flip) { 6544 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6545 } 6546 } 6547 offset += fdof; 6548 } 6549 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6550 } 6551 *size = offset; 6552 PetscFunctionReturn(PETSC_SUCCESS); 6553 } 6554 6555 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6556 { 6557 PetscSection clSection; 6558 IS clPoints; 6559 PetscInt *points = NULL; 6560 const PetscInt *clp, *perm = NULL; 6561 PetscInt depth, numFields, numPoints, asize; 6562 6563 PetscFunctionBeginHot; 6564 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6565 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6566 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6567 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6568 PetscCall(DMPlexGetDepth(dm, &depth)); 6569 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6570 if (depth == 1 && numFields < 2) { 6571 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6572 PetscFunctionReturn(PETSC_SUCCESS); 6573 } 6574 /* Get points */ 6575 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6576 /* Get sizes */ 6577 asize = 0; 6578 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6579 PetscInt dof; 6580 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6581 asize += dof; 6582 } 6583 if (values) { 6584 const PetscScalar *vArray; 6585 PetscInt size; 6586 6587 if (*values) { 6588 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); 6589 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6590 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6591 PetscCall(VecGetArrayRead(v, &vArray)); 6592 /* Get values */ 6593 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6594 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6595 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6596 /* Cleanup array */ 6597 PetscCall(VecRestoreArrayRead(v, &vArray)); 6598 } 6599 if (csize) *csize = asize; 6600 /* Cleanup points */ 6601 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6602 PetscFunctionReturn(PETSC_SUCCESS); 6603 } 6604 6605 /*@C 6606 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6607 6608 Not collective 6609 6610 Input Parameters: 6611 + dm - The `DM` 6612 . section - The section describing the layout in `v`, or `NULL` to use the default section 6613 . v - The local vector 6614 - point - The point in the `DM` 6615 6616 Input/Output Parameters: 6617 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6618 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6619 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6620 6621 Level: intermediate 6622 6623 Notes: 6624 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6625 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6626 assembly function, and a user may already have allocated storage for this operation. 6627 6628 A typical use could be 6629 .vb 6630 values = NULL; 6631 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6632 for (cl = 0; cl < clSize; ++cl) { 6633 <Compute on closure> 6634 } 6635 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6636 .ve 6637 or 6638 .vb 6639 PetscMalloc1(clMaxSize, &values); 6640 for (p = pStart; p < pEnd; ++p) { 6641 clSize = clMaxSize; 6642 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6643 for (cl = 0; cl < clSize; ++cl) { 6644 <Compute on closure> 6645 } 6646 } 6647 PetscFree(values); 6648 .ve 6649 6650 Fortran Notes: 6651 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6652 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6653 6654 `values` must be declared with 6655 .vb 6656 PetscScalar,dimension(:),pointer :: values 6657 .ve 6658 and it will be allocated internally by PETSc to hold the values returned 6659 6660 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6661 @*/ 6662 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6663 { 6664 PetscFunctionBeginHot; 6665 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6666 PetscFunctionReturn(PETSC_SUCCESS); 6667 } 6668 6669 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6670 { 6671 DMLabel depthLabel; 6672 PetscSection clSection; 6673 IS clPoints; 6674 PetscScalar *array; 6675 const PetscScalar *vArray; 6676 PetscInt *points = NULL; 6677 const PetscInt *clp, *perm = NULL; 6678 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6679 6680 PetscFunctionBeginHot; 6681 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6682 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6683 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6684 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6685 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6686 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6687 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6688 if (mdepth == 1 && numFields < 2) { 6689 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6690 PetscFunctionReturn(PETSC_SUCCESS); 6691 } 6692 /* Get points */ 6693 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6694 for (clsize = 0, p = 0; p < Np; p++) { 6695 PetscInt dof; 6696 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6697 clsize += dof; 6698 } 6699 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6700 /* Filter points */ 6701 for (p = 0; p < numPoints * 2; p += 2) { 6702 PetscInt dep; 6703 6704 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6705 if (dep != depth) continue; 6706 points[Np * 2 + 0] = points[p]; 6707 points[Np * 2 + 1] = points[p + 1]; 6708 ++Np; 6709 } 6710 /* Get array */ 6711 if (!values || !*values) { 6712 PetscInt asize = 0, dof; 6713 6714 for (p = 0; p < Np * 2; p += 2) { 6715 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6716 asize += dof; 6717 } 6718 if (!values) { 6719 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6720 if (csize) *csize = asize; 6721 PetscFunctionReturn(PETSC_SUCCESS); 6722 } 6723 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6724 } else { 6725 array = *values; 6726 } 6727 PetscCall(VecGetArrayRead(v, &vArray)); 6728 /* Get values */ 6729 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6730 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6731 /* Cleanup points */ 6732 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6733 /* Cleanup array */ 6734 PetscCall(VecRestoreArrayRead(v, &vArray)); 6735 if (!*values) { 6736 if (csize) *csize = size; 6737 *values = array; 6738 } else { 6739 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6740 *csize = size; 6741 } 6742 PetscFunctionReturn(PETSC_SUCCESS); 6743 } 6744 6745 /*@C 6746 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6747 6748 Not collective 6749 6750 Input Parameters: 6751 + dm - The `DM` 6752 . section - The section describing the layout in `v`, or `NULL` to use the default section 6753 . v - The local vector 6754 . point - The point in the `DM` 6755 . csize - The number of values in the closure, or `NULL` 6756 - values - The array of values 6757 6758 Level: intermediate 6759 6760 Note: 6761 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6762 6763 Fortran Note: 6764 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6765 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6766 6767 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6768 @*/ 6769 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6770 { 6771 PetscInt size = 0; 6772 6773 PetscFunctionBegin; 6774 /* Should work without recalculating size */ 6775 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6776 *values = NULL; 6777 PetscFunctionReturn(PETSC_SUCCESS); 6778 } 6779 6780 static inline void add(PetscScalar *x, PetscScalar y) 6781 { 6782 *x += y; 6783 } 6784 static inline void insert(PetscScalar *x, PetscScalar y) 6785 { 6786 *x = y; 6787 } 6788 6789 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[]) 6790 { 6791 PetscInt cdof; /* The number of constraints on this point */ 6792 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6793 PetscScalar *a; 6794 PetscInt off, cind = 0, k; 6795 6796 PetscFunctionBegin; 6797 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6798 PetscCall(PetscSectionGetOffset(section, point, &off)); 6799 a = &array[off]; 6800 if (!cdof || setBC) { 6801 if (clperm) { 6802 if (perm) { 6803 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6804 } else { 6805 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6806 } 6807 } else { 6808 if (perm) { 6809 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6810 } else { 6811 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6812 } 6813 } 6814 } else { 6815 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6816 if (clperm) { 6817 if (perm) { 6818 for (k = 0; k < dof; ++k) { 6819 if ((cind < cdof) && (k == cdofs[cind])) { 6820 ++cind; 6821 continue; 6822 } 6823 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6824 } 6825 } else { 6826 for (k = 0; k < dof; ++k) { 6827 if ((cind < cdof) && (k == cdofs[cind])) { 6828 ++cind; 6829 continue; 6830 } 6831 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6832 } 6833 } 6834 } else { 6835 if (perm) { 6836 for (k = 0; k < dof; ++k) { 6837 if ((cind < cdof) && (k == cdofs[cind])) { 6838 ++cind; 6839 continue; 6840 } 6841 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6842 } 6843 } else { 6844 for (k = 0; k < dof; ++k) { 6845 if ((cind < cdof) && (k == cdofs[cind])) { 6846 ++cind; 6847 continue; 6848 } 6849 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6850 } 6851 } 6852 } 6853 } 6854 PetscFunctionReturn(PETSC_SUCCESS); 6855 } 6856 6857 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[]) 6858 { 6859 PetscInt cdof; /* The number of constraints on this point */ 6860 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6861 PetscScalar *a; 6862 PetscInt off, cind = 0, k; 6863 6864 PetscFunctionBegin; 6865 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6866 PetscCall(PetscSectionGetOffset(section, point, &off)); 6867 a = &array[off]; 6868 if (cdof) { 6869 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6870 if (clperm) { 6871 if (perm) { 6872 for (k = 0; k < dof; ++k) { 6873 if ((cind < cdof) && (k == cdofs[cind])) { 6874 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6875 cind++; 6876 } 6877 } 6878 } else { 6879 for (k = 0; k < dof; ++k) { 6880 if ((cind < cdof) && (k == cdofs[cind])) { 6881 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6882 cind++; 6883 } 6884 } 6885 } 6886 } else { 6887 if (perm) { 6888 for (k = 0; k < dof; ++k) { 6889 if ((cind < cdof) && (k == cdofs[cind])) { 6890 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6891 cind++; 6892 } 6893 } 6894 } else { 6895 for (k = 0; k < dof; ++k) { 6896 if ((cind < cdof) && (k == cdofs[cind])) { 6897 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6898 cind++; 6899 } 6900 } 6901 } 6902 } 6903 } 6904 PetscFunctionReturn(PETSC_SUCCESS); 6905 } 6906 6907 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[]) 6908 { 6909 PetscScalar *a; 6910 PetscInt fdof, foff, fcdof, foffset = *offset; 6911 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6912 PetscInt cind = 0, b; 6913 6914 PetscFunctionBegin; 6915 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6916 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6917 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6918 a = &array[foff]; 6919 if (!fcdof || setBC) { 6920 if (clperm) { 6921 if (perm) { 6922 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6923 } else { 6924 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6925 } 6926 } else { 6927 if (perm) { 6928 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6929 } else { 6930 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6931 } 6932 } 6933 } else { 6934 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6935 if (clperm) { 6936 if (perm) { 6937 for (b = 0; b < fdof; b++) { 6938 if ((cind < fcdof) && (b == fcdofs[cind])) { 6939 ++cind; 6940 continue; 6941 } 6942 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6943 } 6944 } else { 6945 for (b = 0; b < fdof; b++) { 6946 if ((cind < fcdof) && (b == fcdofs[cind])) { 6947 ++cind; 6948 continue; 6949 } 6950 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6951 } 6952 } 6953 } else { 6954 if (perm) { 6955 for (b = 0; b < fdof; b++) { 6956 if ((cind < fcdof) && (b == fcdofs[cind])) { 6957 ++cind; 6958 continue; 6959 } 6960 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6961 } 6962 } else { 6963 for (b = 0; b < fdof; b++) { 6964 if ((cind < fcdof) && (b == fcdofs[cind])) { 6965 ++cind; 6966 continue; 6967 } 6968 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6969 } 6970 } 6971 } 6972 } 6973 *offset += fdof; 6974 PetscFunctionReturn(PETSC_SUCCESS); 6975 } 6976 6977 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[]) 6978 { 6979 PetscScalar *a; 6980 PetscInt fdof, foff, fcdof, foffset = *offset; 6981 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6982 PetscInt Nc, cind = 0, ncind = 0, b; 6983 PetscBool ncSet, fcSet; 6984 6985 PetscFunctionBegin; 6986 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6987 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6988 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6989 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6990 a = &array[foff]; 6991 if (fcdof) { 6992 /* We just override fcdof and fcdofs with Ncc and comps */ 6993 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6994 if (clperm) { 6995 if (perm) { 6996 if (comps) { 6997 for (b = 0; b < fdof; b++) { 6998 ncSet = fcSet = PETSC_FALSE; 6999 if (b % Nc == comps[ncind]) { 7000 ncind = (ncind + 1) % Ncc; 7001 ncSet = PETSC_TRUE; 7002 } 7003 if ((cind < fcdof) && (b == fcdofs[cind])) { 7004 ++cind; 7005 fcSet = PETSC_TRUE; 7006 } 7007 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7008 } 7009 } else { 7010 for (b = 0; b < fdof; b++) { 7011 if ((cind < fcdof) && (b == fcdofs[cind])) { 7012 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7013 ++cind; 7014 } 7015 } 7016 } 7017 } else { 7018 if (comps) { 7019 for (b = 0; b < fdof; b++) { 7020 ncSet = fcSet = PETSC_FALSE; 7021 if (b % Nc == comps[ncind]) { 7022 ncind = (ncind + 1) % Ncc; 7023 ncSet = PETSC_TRUE; 7024 } 7025 if ((cind < fcdof) && (b == fcdofs[cind])) { 7026 ++cind; 7027 fcSet = PETSC_TRUE; 7028 } 7029 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7030 } 7031 } else { 7032 for (b = 0; b < fdof; b++) { 7033 if ((cind < fcdof) && (b == fcdofs[cind])) { 7034 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7035 ++cind; 7036 } 7037 } 7038 } 7039 } 7040 } else { 7041 if (perm) { 7042 if (comps) { 7043 for (b = 0; b < fdof; b++) { 7044 ncSet = fcSet = PETSC_FALSE; 7045 if (b % Nc == comps[ncind]) { 7046 ncind = (ncind + 1) % Ncc; 7047 ncSet = PETSC_TRUE; 7048 } 7049 if ((cind < fcdof) && (b == fcdofs[cind])) { 7050 ++cind; 7051 fcSet = PETSC_TRUE; 7052 } 7053 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7054 } 7055 } else { 7056 for (b = 0; b < fdof; b++) { 7057 if ((cind < fcdof) && (b == fcdofs[cind])) { 7058 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7059 ++cind; 7060 } 7061 } 7062 } 7063 } else { 7064 if (comps) { 7065 for (b = 0; b < fdof; b++) { 7066 ncSet = fcSet = PETSC_FALSE; 7067 if (b % Nc == comps[ncind]) { 7068 ncind = (ncind + 1) % Ncc; 7069 ncSet = PETSC_TRUE; 7070 } 7071 if ((cind < fcdof) && (b == fcdofs[cind])) { 7072 ++cind; 7073 fcSet = PETSC_TRUE; 7074 } 7075 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7076 } 7077 } else { 7078 for (b = 0; b < fdof; b++) { 7079 if ((cind < fcdof) && (b == fcdofs[cind])) { 7080 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7081 ++cind; 7082 } 7083 } 7084 } 7085 } 7086 } 7087 } 7088 *offset += fdof; 7089 PetscFunctionReturn(PETSC_SUCCESS); 7090 } 7091 7092 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7093 { 7094 PetscScalar *array; 7095 const PetscInt *cone, *coneO; 7096 PetscInt pStart, pEnd, p, numPoints, off, dof; 7097 7098 PetscFunctionBeginHot; 7099 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7100 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7101 PetscCall(DMPlexGetCone(dm, point, &cone)); 7102 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7103 PetscCall(VecGetArray(v, &array)); 7104 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7105 const PetscInt cp = !p ? point : cone[p - 1]; 7106 const PetscInt o = !p ? 0 : coneO[p - 1]; 7107 7108 if ((cp < pStart) || (cp >= pEnd)) { 7109 dof = 0; 7110 continue; 7111 } 7112 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7113 /* ADD_VALUES */ 7114 { 7115 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7116 PetscScalar *a; 7117 PetscInt cdof, coff, cind = 0, k; 7118 7119 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7120 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7121 a = &array[coff]; 7122 if (!cdof) { 7123 if (o >= 0) { 7124 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7125 } else { 7126 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7127 } 7128 } else { 7129 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7130 if (o >= 0) { 7131 for (k = 0; k < dof; ++k) { 7132 if ((cind < cdof) && (k == cdofs[cind])) { 7133 ++cind; 7134 continue; 7135 } 7136 a[k] += values[off + k]; 7137 } 7138 } else { 7139 for (k = 0; k < dof; ++k) { 7140 if ((cind < cdof) && (k == cdofs[cind])) { 7141 ++cind; 7142 continue; 7143 } 7144 a[k] += values[off + dof - k - 1]; 7145 } 7146 } 7147 } 7148 } 7149 } 7150 PetscCall(VecRestoreArray(v, &array)); 7151 PetscFunctionReturn(PETSC_SUCCESS); 7152 } 7153 7154 /*@C 7155 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7156 7157 Not collective 7158 7159 Input Parameters: 7160 + dm - The `DM` 7161 . section - The section describing the layout in `v`, or `NULL` to use the default section 7162 . v - The local vector 7163 . point - The point in the `DM` 7164 . values - The array of values 7165 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7166 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7167 7168 Level: intermediate 7169 7170 Note: 7171 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7172 7173 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7174 @*/ 7175 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7176 { 7177 PetscSection clSection; 7178 IS clPoints; 7179 PetscScalar *array; 7180 PetscInt *points = NULL; 7181 const PetscInt *clp, *clperm = NULL; 7182 PetscInt depth, numFields, numPoints, p, clsize; 7183 7184 PetscFunctionBeginHot; 7185 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7186 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7187 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7188 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7189 PetscCall(DMPlexGetDepth(dm, &depth)); 7190 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7191 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7192 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7193 PetscFunctionReturn(PETSC_SUCCESS); 7194 } 7195 /* Get points */ 7196 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7197 for (clsize = 0, p = 0; p < numPoints; p++) { 7198 PetscInt dof; 7199 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7200 clsize += dof; 7201 } 7202 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7203 /* Get array */ 7204 PetscCall(VecGetArray(v, &array)); 7205 /* Get values */ 7206 if (numFields > 0) { 7207 PetscInt offset = 0, f; 7208 for (f = 0; f < numFields; ++f) { 7209 const PetscInt **perms = NULL; 7210 const PetscScalar **flips = NULL; 7211 7212 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7213 switch (mode) { 7214 case INSERT_VALUES: 7215 for (p = 0; p < numPoints; p++) { 7216 const PetscInt point = points[2 * p]; 7217 const PetscInt *perm = perms ? perms[p] : NULL; 7218 const PetscScalar *flip = flips ? flips[p] : NULL; 7219 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7220 } 7221 break; 7222 case INSERT_ALL_VALUES: 7223 for (p = 0; p < numPoints; p++) { 7224 const PetscInt point = points[2 * p]; 7225 const PetscInt *perm = perms ? perms[p] : NULL; 7226 const PetscScalar *flip = flips ? flips[p] : NULL; 7227 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7228 } 7229 break; 7230 case INSERT_BC_VALUES: 7231 for (p = 0; p < numPoints; p++) { 7232 const PetscInt point = points[2 * p]; 7233 const PetscInt *perm = perms ? perms[p] : NULL; 7234 const PetscScalar *flip = flips ? flips[p] : NULL; 7235 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7236 } 7237 break; 7238 case ADD_VALUES: 7239 for (p = 0; p < numPoints; p++) { 7240 const PetscInt point = points[2 * p]; 7241 const PetscInt *perm = perms ? perms[p] : NULL; 7242 const PetscScalar *flip = flips ? flips[p] : NULL; 7243 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7244 } 7245 break; 7246 case ADD_ALL_VALUES: 7247 for (p = 0; p < numPoints; p++) { 7248 const PetscInt point = points[2 * p]; 7249 const PetscInt *perm = perms ? perms[p] : NULL; 7250 const PetscScalar *flip = flips ? flips[p] : NULL; 7251 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7252 } 7253 break; 7254 case ADD_BC_VALUES: 7255 for (p = 0; p < numPoints; p++) { 7256 const PetscInt point = points[2 * p]; 7257 const PetscInt *perm = perms ? perms[p] : NULL; 7258 const PetscScalar *flip = flips ? flips[p] : NULL; 7259 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7260 } 7261 break; 7262 default: 7263 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7264 } 7265 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7266 } 7267 } else { 7268 PetscInt dof, off; 7269 const PetscInt **perms = NULL; 7270 const PetscScalar **flips = NULL; 7271 7272 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7273 switch (mode) { 7274 case INSERT_VALUES: 7275 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7276 const PetscInt point = points[2 * p]; 7277 const PetscInt *perm = perms ? perms[p] : NULL; 7278 const PetscScalar *flip = flips ? flips[p] : NULL; 7279 PetscCall(PetscSectionGetDof(section, point, &dof)); 7280 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7281 } 7282 break; 7283 case INSERT_ALL_VALUES: 7284 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7285 const PetscInt point = points[2 * p]; 7286 const PetscInt *perm = perms ? perms[p] : NULL; 7287 const PetscScalar *flip = flips ? flips[p] : NULL; 7288 PetscCall(PetscSectionGetDof(section, point, &dof)); 7289 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7290 } 7291 break; 7292 case INSERT_BC_VALUES: 7293 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7294 const PetscInt point = points[2 * p]; 7295 const PetscInt *perm = perms ? perms[p] : NULL; 7296 const PetscScalar *flip = flips ? flips[p] : NULL; 7297 PetscCall(PetscSectionGetDof(section, point, &dof)); 7298 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7299 } 7300 break; 7301 case ADD_VALUES: 7302 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 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(PetscSectionGetDof(section, point, &dof)); 7307 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7308 } 7309 break; 7310 case ADD_ALL_VALUES: 7311 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7312 const PetscInt point = points[2 * p]; 7313 const PetscInt *perm = perms ? perms[p] : NULL; 7314 const PetscScalar *flip = flips ? flips[p] : NULL; 7315 PetscCall(PetscSectionGetDof(section, point, &dof)); 7316 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7317 } 7318 break; 7319 case ADD_BC_VALUES: 7320 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7321 const PetscInt point = points[2 * p]; 7322 const PetscInt *perm = perms ? perms[p] : NULL; 7323 const PetscScalar *flip = flips ? flips[p] : NULL; 7324 PetscCall(PetscSectionGetDof(section, point, &dof)); 7325 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7326 } 7327 break; 7328 default: 7329 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7330 } 7331 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7332 } 7333 /* Cleanup points */ 7334 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7335 /* Cleanup array */ 7336 PetscCall(VecRestoreArray(v, &array)); 7337 PetscFunctionReturn(PETSC_SUCCESS); 7338 } 7339 7340 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7341 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7342 { 7343 PetscFunctionBegin; 7344 *contains = PETSC_TRUE; 7345 if (label) { 7346 PetscInt fdof; 7347 7348 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7349 if (!*contains) { 7350 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7351 *offset += fdof; 7352 PetscFunctionReturn(PETSC_SUCCESS); 7353 } 7354 } 7355 PetscFunctionReturn(PETSC_SUCCESS); 7356 } 7357 7358 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7359 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) 7360 { 7361 PetscSection clSection; 7362 IS clPoints; 7363 PetscScalar *array; 7364 PetscInt *points = NULL; 7365 const PetscInt *clp; 7366 PetscInt numFields, numPoints, p; 7367 PetscInt offset = 0, f; 7368 7369 PetscFunctionBeginHot; 7370 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7371 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7372 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7373 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7374 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7375 /* Get points */ 7376 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7377 /* Get array */ 7378 PetscCall(VecGetArray(v, &array)); 7379 /* Get values */ 7380 for (f = 0; f < numFields; ++f) { 7381 const PetscInt **perms = NULL; 7382 const PetscScalar **flips = NULL; 7383 PetscBool contains; 7384 7385 if (!fieldActive[f]) { 7386 for (p = 0; p < numPoints * 2; p += 2) { 7387 PetscInt fdof; 7388 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7389 offset += fdof; 7390 } 7391 continue; 7392 } 7393 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7394 switch (mode) { 7395 case INSERT_VALUES: 7396 for (p = 0; p < numPoints; p++) { 7397 const PetscInt point = points[2 * p]; 7398 const PetscInt *perm = perms ? perms[p] : NULL; 7399 const PetscScalar *flip = flips ? flips[p] : NULL; 7400 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7401 if (!contains) continue; 7402 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7403 } 7404 break; 7405 case INSERT_ALL_VALUES: 7406 for (p = 0; p < numPoints; p++) { 7407 const PetscInt point = points[2 * p]; 7408 const PetscInt *perm = perms ? perms[p] : NULL; 7409 const PetscScalar *flip = flips ? flips[p] : NULL; 7410 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7411 if (!contains) continue; 7412 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7413 } 7414 break; 7415 case INSERT_BC_VALUES: 7416 for (p = 0; p < numPoints; p++) { 7417 const PetscInt point = points[2 * p]; 7418 const PetscInt *perm = perms ? perms[p] : NULL; 7419 const PetscScalar *flip = flips ? flips[p] : NULL; 7420 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7421 if (!contains) continue; 7422 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7423 } 7424 break; 7425 case ADD_VALUES: 7426 for (p = 0; p < numPoints; p++) { 7427 const PetscInt point = points[2 * p]; 7428 const PetscInt *perm = perms ? perms[p] : NULL; 7429 const PetscScalar *flip = flips ? flips[p] : NULL; 7430 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7431 if (!contains) continue; 7432 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7433 } 7434 break; 7435 case ADD_ALL_VALUES: 7436 for (p = 0; p < numPoints; p++) { 7437 const PetscInt point = points[2 * p]; 7438 const PetscInt *perm = perms ? perms[p] : NULL; 7439 const PetscScalar *flip = flips ? flips[p] : NULL; 7440 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7441 if (!contains) continue; 7442 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7443 } 7444 break; 7445 default: 7446 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7447 } 7448 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7449 } 7450 /* Cleanup points */ 7451 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7452 /* Cleanup array */ 7453 PetscCall(VecRestoreArray(v, &array)); 7454 PetscFunctionReturn(PETSC_SUCCESS); 7455 } 7456 7457 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7458 { 7459 PetscMPIInt rank; 7460 PetscInt i, j; 7461 7462 PetscFunctionBegin; 7463 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7464 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7465 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7466 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7467 numCIndices = numCIndices ? numCIndices : numRIndices; 7468 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7469 for (i = 0; i < numRIndices; i++) { 7470 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7471 for (j = 0; j < numCIndices; j++) { 7472 #if defined(PETSC_USE_COMPLEX) 7473 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7474 #else 7475 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7476 #endif 7477 } 7478 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7479 } 7480 PetscFunctionReturn(PETSC_SUCCESS); 7481 } 7482 7483 /* 7484 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7485 7486 Input Parameters: 7487 + section - The section for this data layout 7488 . islocal - Is the section (and thus indices being requested) local or global? 7489 . point - The point contributing dofs with these indices 7490 . off - The global offset of this point 7491 . loff - The local offset of each field 7492 . setBC - The flag determining whether to include indices of boundary values 7493 . perm - A permutation of the dofs on this point, or NULL 7494 - indperm - A permutation of the entire indices array, or NULL 7495 7496 Output Parameter: 7497 . indices - Indices for dofs on this point 7498 7499 Level: developer 7500 7501 Note: The indices could be local or global, depending on the value of 'off'. 7502 */ 7503 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7504 { 7505 PetscInt dof; /* The number of unknowns on this point */ 7506 PetscInt cdof; /* The number of constraints on this point */ 7507 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7508 PetscInt cind = 0, k; 7509 7510 PetscFunctionBegin; 7511 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7512 PetscCall(PetscSectionGetDof(section, point, &dof)); 7513 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7514 if (!cdof || setBC) { 7515 for (k = 0; k < dof; ++k) { 7516 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7517 const PetscInt ind = indperm ? indperm[preind] : preind; 7518 7519 indices[ind] = off + k; 7520 } 7521 } else { 7522 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7523 for (k = 0; k < dof; ++k) { 7524 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7525 const PetscInt ind = indperm ? indperm[preind] : preind; 7526 7527 if ((cind < cdof) && (k == cdofs[cind])) { 7528 /* Insert check for returning constrained indices */ 7529 indices[ind] = -(off + k + 1); 7530 ++cind; 7531 } else { 7532 indices[ind] = off + k - (islocal ? 0 : cind); 7533 } 7534 } 7535 } 7536 *loff += dof; 7537 PetscFunctionReturn(PETSC_SUCCESS); 7538 } 7539 7540 /* 7541 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7542 7543 Input Parameters: 7544 + section - a section (global or local) 7545 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7546 . point - point within section 7547 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7548 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7549 . setBC - identify constrained (boundary condition) points via involution. 7550 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7551 . permsoff - offset 7552 - indperm - index permutation 7553 7554 Output Parameter: 7555 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7556 . indices - array to hold indices (as defined by section) of each dof associated with point 7557 7558 Notes: 7559 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7560 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7561 in the local vector. 7562 7563 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7564 significant). It is invalid to call with a global section and setBC=true. 7565 7566 Developer Note: 7567 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7568 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7569 offset could be obtained from the section instead of passing it explicitly as we do now. 7570 7571 Example: 7572 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7573 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7574 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7575 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. 7576 7577 Level: developer 7578 */ 7579 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[]) 7580 { 7581 PetscInt numFields, foff, f; 7582 7583 PetscFunctionBegin; 7584 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7585 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7586 for (f = 0, foff = 0; f < numFields; ++f) { 7587 PetscInt fdof, cfdof; 7588 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7589 PetscInt cind = 0, b; 7590 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7591 7592 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7593 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7594 if (!cfdof || setBC) { 7595 for (b = 0; b < fdof; ++b) { 7596 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7597 const PetscInt ind = indperm ? indperm[preind] : preind; 7598 7599 indices[ind] = off + foff + b; 7600 } 7601 } else { 7602 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7603 for (b = 0; b < fdof; ++b) { 7604 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7605 const PetscInt ind = indperm ? indperm[preind] : preind; 7606 7607 if ((cind < cfdof) && (b == fcdofs[cind])) { 7608 indices[ind] = -(off + foff + b + 1); 7609 ++cind; 7610 } else { 7611 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7612 } 7613 } 7614 } 7615 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7616 foffs[f] += fdof; 7617 } 7618 PetscFunctionReturn(PETSC_SUCCESS); 7619 } 7620 7621 /* 7622 This version believes the globalSection offsets for each field, rather than just the point offset 7623 7624 . foffs - The offset into 'indices' for each field, since it is segregated by field 7625 7626 Notes: 7627 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7628 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7629 */ 7630 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7631 { 7632 PetscInt numFields, foff, f; 7633 7634 PetscFunctionBegin; 7635 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7636 for (f = 0; f < numFields; ++f) { 7637 PetscInt fdof, cfdof; 7638 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7639 PetscInt cind = 0, b; 7640 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7641 7642 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7643 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7644 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7645 if (!cfdof) { 7646 for (b = 0; b < fdof; ++b) { 7647 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7648 const PetscInt ind = indperm ? indperm[preind] : preind; 7649 7650 indices[ind] = foff + b; 7651 } 7652 } else { 7653 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7654 for (b = 0; b < fdof; ++b) { 7655 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7656 const PetscInt ind = indperm ? indperm[preind] : preind; 7657 7658 if ((cind < cfdof) && (b == fcdofs[cind])) { 7659 indices[ind] = -(foff + b + 1); 7660 ++cind; 7661 } else { 7662 indices[ind] = foff + b - cind; 7663 } 7664 } 7665 } 7666 foffs[f] += fdof; 7667 } 7668 PetscFunctionReturn(PETSC_SUCCESS); 7669 } 7670 7671 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7672 { 7673 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7674 7675 PetscFunctionBegin; 7676 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7677 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7678 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7679 for (PetscInt p = 0; p < nPoints; p++) { 7680 PetscInt b = pnts[2 * p]; 7681 PetscInt bSecDof = 0, bOff; 7682 PetscInt cSecDof = 0; 7683 PetscSection indices_section; 7684 7685 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7686 if (!bSecDof) continue; 7687 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7688 indices_section = cSecDof > 0 ? cSec : section; 7689 if (numFields) { 7690 PetscInt fStart[32], fEnd[32]; 7691 7692 fStart[0] = 0; 7693 fEnd[0] = 0; 7694 for (PetscInt f = 0; f < numFields; f++) { 7695 PetscInt fDof = 0; 7696 7697 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7698 fStart[f + 1] = fStart[f] + fDof; 7699 fEnd[f + 1] = fStart[f + 1]; 7700 } 7701 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7702 // only apply permutations on one side 7703 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7704 for (PetscInt f = 0; f < numFields; f++) { 7705 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7706 } 7707 } else { 7708 PetscInt bEnd = 0; 7709 7710 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7711 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7712 7713 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7714 } 7715 } 7716 PetscFunctionReturn(PETSC_SUCCESS); 7717 } 7718 7719 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[]) 7720 { 7721 Mat cMat; 7722 PetscSection aSec, cSec; 7723 IS aIS; 7724 PetscInt aStart = -1, aEnd = -1; 7725 PetscInt sStart = -1, sEnd = -1; 7726 PetscInt cStart = -1, cEnd = -1; 7727 const PetscInt *anchors; 7728 PetscInt numFields, p; 7729 PetscInt newNumPoints = 0, newNumIndices = 0; 7730 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7731 PetscInt oldOffsets[32]; 7732 PetscInt newOffsets[32]; 7733 PetscInt oldOffsetsCopy[32]; 7734 PetscInt newOffsetsCopy[32]; 7735 PetscScalar *modMat = NULL; 7736 PetscBool anyConstrained = PETSC_FALSE; 7737 7738 PetscFunctionBegin; 7739 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7740 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7741 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7742 7743 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7744 /* if there are point-to-point constraints */ 7745 if (aSec) { 7746 PetscCall(PetscArrayzero(newOffsets, 32)); 7747 PetscCall(PetscArrayzero(oldOffsets, 32)); 7748 PetscCall(ISGetIndices(aIS, &anchors)); 7749 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7750 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7751 /* figure out how many points are going to be in the new element matrix 7752 * (we allow double counting, because it's all just going to be summed 7753 * into the global matrix anyway) */ 7754 for (p = 0; p < 2 * numPoints; p += 2) { 7755 PetscInt b = points[p]; 7756 PetscInt bDof = 0, bSecDof = 0; 7757 7758 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7759 if (!bSecDof) continue; 7760 7761 for (PetscInt f = 0; f < numFields; f++) { 7762 PetscInt fDof = 0; 7763 7764 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7765 oldOffsets[f + 1] += fDof; 7766 } 7767 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7768 if (bDof) { 7769 /* this point is constrained */ 7770 /* it is going to be replaced by its anchors */ 7771 PetscInt bOff, q; 7772 7773 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7774 for (q = 0; q < bDof; q++) { 7775 PetscInt a = anchors[bOff + q]; 7776 PetscInt aDof = 0; 7777 7778 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7779 if (aDof) { 7780 anyConstrained = PETSC_TRUE; 7781 newNumPoints += 1; 7782 } 7783 newNumIndices += aDof; 7784 for (PetscInt f = 0; f < numFields; ++f) { 7785 PetscInt fDof = 0; 7786 7787 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7788 newOffsets[f + 1] += fDof; 7789 } 7790 } 7791 } else { 7792 /* this point is not constrained */ 7793 newNumPoints++; 7794 newNumIndices += bSecDof; 7795 for (PetscInt f = 0; f < numFields; ++f) { 7796 PetscInt fDof; 7797 7798 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7799 newOffsets[f + 1] += fDof; 7800 } 7801 } 7802 } 7803 } 7804 if (!anyConstrained) { 7805 if (outNumPoints) *outNumPoints = 0; 7806 if (outNumIndices) *outNumIndices = 0; 7807 if (outPoints) *outPoints = NULL; 7808 if (outMat) *outMat = NULL; 7809 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7810 PetscFunctionReturn(PETSC_SUCCESS); 7811 } 7812 7813 if (outNumPoints) *outNumPoints = newNumPoints; 7814 if (outNumIndices) *outNumIndices = newNumIndices; 7815 7816 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7817 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7818 7819 if (!outPoints && !outMat) { 7820 if (offsets) { 7821 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7822 } 7823 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7824 PetscFunctionReturn(PETSC_SUCCESS); 7825 } 7826 7827 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7828 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7829 7830 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7831 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7832 7833 /* output arrays */ 7834 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7835 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7836 7837 // get the new Points 7838 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7839 PetscInt b = points[2 * p]; 7840 PetscInt bDof = 0, bSecDof = 0, bOff; 7841 7842 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7843 if (!bSecDof) continue; 7844 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7845 if (bDof) { 7846 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7847 for (PetscInt q = 0; q < bDof; q++) { 7848 PetscInt a = anchors[bOff + q], aDof = 0; 7849 7850 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7851 if (aDof) { 7852 newPoints[2 * newP] = a; 7853 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7854 newP++; 7855 } 7856 } 7857 } else { 7858 newPoints[2 * newP] = b; 7859 newPoints[2 * newP + 1] = points[2 * p + 1]; 7860 newP++; 7861 } 7862 } 7863 7864 if (outMat) { 7865 PetscScalar *tmpMat; 7866 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7867 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7868 7869 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7870 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7871 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7872 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7873 7874 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7875 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7876 7877 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7878 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7879 7880 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7881 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7882 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7883 // for each field, insert the anchor modification into modMat 7884 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7885 PetscInt fStart = oldOffsets[f]; 7886 PetscInt fNewStart = newOffsets[f]; 7887 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7888 PetscInt b = points[2 * p]; 7889 PetscInt bDof = 0, bSecDof = 0, bOff; 7890 7891 if (b >= sStart && b < sEnd) { 7892 if (numFields) { 7893 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7894 } else { 7895 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7896 } 7897 } 7898 if (!bSecDof) continue; 7899 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7900 if (bDof) { 7901 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7902 for (PetscInt q = 0; q < bDof; q++, newP++) { 7903 PetscInt a = anchors[bOff + q], aDof = 0; 7904 7905 if (a >= sStart && a < sEnd) { 7906 if (numFields) { 7907 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7908 } else { 7909 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7910 } 7911 } 7912 if (aDof) { 7913 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7914 for (PetscInt d = 0; d < bSecDof; d++) { 7915 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7916 } 7917 } 7918 oNew += aDof; 7919 } 7920 } else { 7921 // Insert the identity matrix in this block 7922 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7923 oNew += bSecDof; 7924 newP++; 7925 } 7926 o += bSecDof; 7927 } 7928 } 7929 7930 *outMat = modMat; 7931 7932 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7933 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7934 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7935 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7936 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7937 } 7938 PetscCall(ISRestoreIndices(aIS, &anchors)); 7939 7940 /* output */ 7941 if (outPoints) { 7942 *outPoints = newPoints; 7943 } else { 7944 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7945 } 7946 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7947 PetscFunctionReturn(PETSC_SUCCESS); 7948 } 7949 7950 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) 7951 { 7952 PetscScalar *modMat = NULL; 7953 PetscInt newNumIndices = -1; 7954 7955 PetscFunctionBegin; 7956 /* 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. 7957 modMat is that matrix C */ 7958 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7959 if (outNumIndices) *outNumIndices = newNumIndices; 7960 if (modMat) { 7961 const PetscScalar *newValues = values; 7962 7963 if (multiplyRight) { 7964 PetscScalar *newNewValues = NULL; 7965 PetscBLASInt M, N, K; 7966 PetscScalar a = 1.0, b = 0.0; 7967 7968 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); 7969 7970 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7971 PetscCall(PetscBLASIntCast(numRows, &N)); 7972 PetscCall(PetscBLASIntCast(numIndices, &K)); 7973 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7974 // row-major to column-major conversion, right multiplication becomes left multiplication 7975 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7976 numCols = newNumIndices; 7977 newValues = newNewValues; 7978 } 7979 7980 if (multiplyLeft) { 7981 PetscScalar *newNewValues = NULL; 7982 PetscBLASInt M, N, K; 7983 PetscScalar a = 1.0, b = 0.0; 7984 7985 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); 7986 7987 PetscCall(PetscBLASIntCast(numCols, &M)); 7988 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7989 PetscCall(PetscBLASIntCast(numIndices, &K)); 7990 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7991 // row-major to column-major conversion, left multiplication becomes right multiplication 7992 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7993 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7994 newValues = newNewValues; 7995 } 7996 *outValues = (PetscScalar *)newValues; 7997 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7998 } 7999 PetscFunctionReturn(PETSC_SUCCESS); 8000 } 8001 8002 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) 8003 { 8004 PetscFunctionBegin; 8005 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 8006 PetscFunctionReturn(PETSC_SUCCESS); 8007 } 8008 8009 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 8010 { 8011 /* Closure ordering */ 8012 PetscSection clSection; 8013 IS clPoints; 8014 const PetscInt *clp; 8015 PetscInt *points; 8016 PetscInt Ncl, Ni = 0; 8017 8018 PetscFunctionBeginHot; 8019 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8020 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 8021 PetscInt dof; 8022 8023 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8024 Ni += dof; 8025 } 8026 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8027 *closureSize = Ni; 8028 PetscFunctionReturn(PETSC_SUCCESS); 8029 } 8030 8031 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) 8032 { 8033 /* Closure ordering */ 8034 PetscSection clSection; 8035 IS clPoints; 8036 const PetscInt *clp; 8037 PetscInt *points; 8038 const PetscInt *clperm = NULL; 8039 /* Dof permutation and sign flips */ 8040 const PetscInt **perms[32] = {NULL}; 8041 const PetscScalar **flips[32] = {NULL}; 8042 PetscScalar *valCopy = NULL; 8043 /* Hanging node constraints */ 8044 PetscInt *pointsC = NULL; 8045 PetscScalar *valuesC = NULL; 8046 PetscInt NclC, NiC; 8047 8048 PetscInt *idx; 8049 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8050 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8051 PetscInt idxStart, idxEnd; 8052 PetscInt nRows, nCols; 8053 8054 PetscFunctionBeginHot; 8055 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8056 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8057 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8058 PetscAssertPointer(numRows, 6); 8059 PetscAssertPointer(numCols, 7); 8060 if (indices) PetscAssertPointer(indices, 8); 8061 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8062 if (values) PetscAssertPointer(values, 10); 8063 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8064 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8065 PetscCall(PetscArrayzero(offsets, 32)); 8066 /* 1) Get points in closure */ 8067 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8068 if (useClPerm) { 8069 PetscInt depth, clsize; 8070 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8071 for (clsize = 0, p = 0; p < Ncl; p++) { 8072 PetscInt dof; 8073 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8074 clsize += dof; 8075 } 8076 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8077 } 8078 /* 2) Get number of indices on these points and field offsets from section */ 8079 for (p = 0; p < Ncl * 2; p += 2) { 8080 PetscInt dof, fdof; 8081 8082 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8083 for (f = 0; f < Nf; ++f) { 8084 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8085 offsets[f + 1] += fdof; 8086 } 8087 Ni += dof; 8088 } 8089 if (*numRows == -1) *numRows = Ni; 8090 if (*numCols == -1) *numCols = Ni; 8091 nRows = *numRows; 8092 nCols = *numCols; 8093 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8094 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8095 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8096 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8097 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8098 for (f = 0; f < PetscMax(1, Nf); ++f) { 8099 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8100 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8101 /* may need to apply sign changes to the element matrix */ 8102 if (values && flips[f]) { 8103 PetscInt foffset = offsets[f]; 8104 8105 for (p = 0; p < Ncl; ++p) { 8106 PetscInt pnt = points[2 * p], fdof; 8107 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8108 8109 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8110 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8111 if (flip) { 8112 PetscInt i, j, k; 8113 8114 if (!valCopy) { 8115 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8116 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8117 *values = valCopy; 8118 } 8119 for (i = 0; i < fdof; ++i) { 8120 PetscScalar fval = flip[i]; 8121 8122 if (multiplyRight) { 8123 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8124 } 8125 if (multiplyLeft) { 8126 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8127 } 8128 } 8129 } 8130 foffset += fdof; 8131 } 8132 } 8133 } 8134 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8135 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8136 if (NclC) { 8137 if (multiplyRight) *numCols = NiC; 8138 if (multiplyLeft) *numRows = NiC; 8139 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8140 for (f = 0; f < PetscMax(1, Nf); ++f) { 8141 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8142 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8143 } 8144 for (f = 0; f < PetscMax(1, Nf); ++f) { 8145 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8146 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8147 } 8148 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8149 Ncl = NclC; 8150 Ni = NiC; 8151 points = pointsC; 8152 if (values) *values = valuesC; 8153 } 8154 /* 5) Calculate indices */ 8155 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8156 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8157 if (Nf) { 8158 PetscInt idxOff; 8159 PetscBool useFieldOffsets; 8160 8161 if (outOffsets) { 8162 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8163 } 8164 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8165 if (useFieldOffsets) { 8166 for (p = 0; p < Ncl; ++p) { 8167 const PetscInt pnt = points[p * 2]; 8168 8169 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8170 } 8171 } else { 8172 for (p = 0; p < Ncl; ++p) { 8173 const PetscInt pnt = points[p * 2]; 8174 8175 if (pnt < idxStart || pnt >= idxEnd) continue; 8176 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8177 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8178 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8179 * global section. */ 8180 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8181 } 8182 } 8183 } else { 8184 PetscInt off = 0, idxOff; 8185 8186 for (p = 0; p < Ncl; ++p) { 8187 const PetscInt pnt = points[p * 2]; 8188 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8189 8190 if (pnt < idxStart || pnt >= idxEnd) continue; 8191 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8192 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8193 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8194 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8195 } 8196 } 8197 /* 6) Cleanup */ 8198 for (f = 0; f < PetscMax(1, Nf); ++f) { 8199 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8200 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8201 } 8202 if (NclC) { 8203 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8204 } else { 8205 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8206 } 8207 8208 if (indices) *indices = idx; 8209 PetscFunctionReturn(PETSC_SUCCESS); 8210 } 8211 8212 /*@C 8213 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8214 8215 Not collective 8216 8217 Input Parameters: 8218 + dm - The `DM` 8219 . section - The `PetscSection` describing the points (a local section) 8220 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8221 . point - The point defining the closure 8222 - useClPerm - Use the closure point permutation if available 8223 8224 Output Parameters: 8225 + numIndices - The number of dof indices in the closure of point with the input sections 8226 . indices - The dof indices 8227 . outOffsets - Array to write the field offsets into, or `NULL` 8228 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8229 8230 Level: advanced 8231 8232 Notes: 8233 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8234 8235 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8236 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8237 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8238 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8239 indices (with the above semantics) are implied. 8240 8241 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8242 `PetscSection`, `DMGetGlobalSection()` 8243 @*/ 8244 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8245 { 8246 PetscInt numRows = -1, numCols = -1; 8247 8248 PetscFunctionBeginHot; 8249 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8250 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8251 *numIndices = numRows; 8252 PetscFunctionReturn(PETSC_SUCCESS); 8253 } 8254 8255 /*@C 8256 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8257 8258 Not collective 8259 8260 Input Parameters: 8261 + dm - The `DM` 8262 . section - The `PetscSection` describing the points (a local section) 8263 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8264 . point - The point defining the closure 8265 - useClPerm - Use the closure point permutation if available 8266 8267 Output Parameters: 8268 + numIndices - The number of dof indices in the closure of point with the input sections 8269 . indices - The dof indices 8270 . outOffsets - Array to write the field offsets into, or `NULL` 8271 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8272 8273 Level: advanced 8274 8275 Notes: 8276 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8277 8278 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8279 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8280 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8281 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8282 indices (with the above semantics) are implied. 8283 8284 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8285 @*/ 8286 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8287 { 8288 PetscFunctionBegin; 8289 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8290 PetscAssertPointer(indices, 7); 8291 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8292 PetscFunctionReturn(PETSC_SUCCESS); 8293 } 8294 8295 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8296 { 8297 DM_Plex *mesh = (DM_Plex *)dm->data; 8298 PetscInt *indices; 8299 PetscInt numIndices; 8300 const PetscScalar *valuesOrig = values; 8301 PetscErrorCode ierr; 8302 8303 PetscFunctionBegin; 8304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8305 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8306 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8307 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8308 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8309 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8310 8311 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8312 8313 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8314 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8315 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8316 if (ierr) { 8317 PetscMPIInt rank; 8318 8319 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8320 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8321 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8322 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8323 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8324 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8325 } 8326 if (mesh->printFEM > 1) { 8327 PetscInt i; 8328 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8329 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8330 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8331 } 8332 8333 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8334 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8335 PetscFunctionReturn(PETSC_SUCCESS); 8336 } 8337 8338 /*@C 8339 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8340 8341 Not collective 8342 8343 Input Parameters: 8344 + dm - The `DM` 8345 . section - The section describing the layout in `v`, or `NULL` to use the default section 8346 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8347 . A - The matrix 8348 . point - The point in the `DM` 8349 . values - The array of values 8350 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8351 8352 Level: intermediate 8353 8354 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8355 @*/ 8356 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8357 { 8358 PetscFunctionBegin; 8359 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8360 PetscFunctionReturn(PETSC_SUCCESS); 8361 } 8362 8363 /*@C 8364 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8365 8366 Not collective 8367 8368 Input Parameters: 8369 + dmRow - The `DM` for the row fields 8370 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8371 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8372 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8373 . dmCol - The `DM` for the column fields 8374 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8375 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8376 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8377 . A - The matrix 8378 . point - The point in the `DM` 8379 . values - The array of values 8380 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8381 8382 Level: intermediate 8383 8384 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8385 @*/ 8386 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) 8387 { 8388 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8389 PetscInt *indicesRow, *indicesCol; 8390 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8391 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8392 8393 PetscErrorCode ierr; 8394 8395 PetscFunctionBegin; 8396 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8397 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8398 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8399 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8400 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8401 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8402 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8403 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8404 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8405 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8406 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8407 8408 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8409 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8410 valuesV1 = valuesV0; 8411 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8412 valuesV2 = valuesV1; 8413 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8414 8415 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8416 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8417 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8418 if (ierr) { 8419 PetscMPIInt rank; 8420 8421 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8422 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8423 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8424 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8425 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8426 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8427 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8428 } 8429 8430 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8431 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8432 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8433 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8434 PetscFunctionReturn(PETSC_SUCCESS); 8435 } 8436 8437 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8438 { 8439 DM_Plex *mesh = (DM_Plex *)dmf->data; 8440 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8441 PetscInt *cpoints = NULL; 8442 PetscInt *findices, *cindices; 8443 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8444 PetscInt foffsets[32], coffsets[32]; 8445 DMPolytopeType ct; 8446 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8447 PetscErrorCode ierr; 8448 8449 PetscFunctionBegin; 8450 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8451 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8452 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8453 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8454 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8455 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8456 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8457 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8458 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8459 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8460 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8461 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8462 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8463 PetscCall(PetscArrayzero(foffsets, 32)); 8464 PetscCall(PetscArrayzero(coffsets, 32)); 8465 /* Column indices */ 8466 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8467 maxFPoints = numCPoints; 8468 /* Compress out points not in the section */ 8469 /* TODO: Squeeze out points with 0 dof as well */ 8470 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8471 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8472 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8473 cpoints[q * 2] = cpoints[p]; 8474 cpoints[q * 2 + 1] = cpoints[p + 1]; 8475 ++q; 8476 } 8477 } 8478 numCPoints = q; 8479 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8480 PetscInt fdof; 8481 8482 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8483 if (!dof) continue; 8484 for (f = 0; f < numFields; ++f) { 8485 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8486 coffsets[f + 1] += fdof; 8487 } 8488 numCIndices += dof; 8489 } 8490 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8491 /* Row indices */ 8492 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8493 { 8494 DMPlexTransform tr; 8495 DMPolytopeType *rct; 8496 PetscInt *rsize, *rcone, *rornt, Nt; 8497 8498 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8499 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8500 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8501 numSubcells = rsize[Nt - 1]; 8502 PetscCall(DMPlexTransformDestroy(&tr)); 8503 } 8504 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8505 for (r = 0, q = 0; r < numSubcells; ++r) { 8506 /* TODO Map from coarse to fine cells */ 8507 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8508 /* Compress out points not in the section */ 8509 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8510 for (p = 0; p < numFPoints * 2; p += 2) { 8511 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8512 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8513 if (!dof) continue; 8514 for (s = 0; s < q; ++s) 8515 if (fpoints[p] == ftotpoints[s * 2]) break; 8516 if (s < q) continue; 8517 ftotpoints[q * 2] = fpoints[p]; 8518 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8519 ++q; 8520 } 8521 } 8522 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8523 } 8524 numFPoints = q; 8525 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8526 PetscInt fdof; 8527 8528 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8529 if (!dof) continue; 8530 for (f = 0; f < numFields; ++f) { 8531 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8532 foffsets[f + 1] += fdof; 8533 } 8534 numFIndices += dof; 8535 } 8536 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8537 8538 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8539 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8540 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8541 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8542 if (numFields) { 8543 const PetscInt **permsF[32] = {NULL}; 8544 const PetscInt **permsC[32] = {NULL}; 8545 8546 for (f = 0; f < numFields; f++) { 8547 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8548 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8549 } 8550 for (p = 0; p < numFPoints; p++) { 8551 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8552 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8553 } 8554 for (p = 0; p < numCPoints; p++) { 8555 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8556 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8557 } 8558 for (f = 0; f < numFields; f++) { 8559 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8560 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8561 } 8562 } else { 8563 const PetscInt **permsF = NULL; 8564 const PetscInt **permsC = NULL; 8565 8566 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8567 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8568 for (p = 0, off = 0; p < numFPoints; p++) { 8569 const PetscInt *perm = permsF ? permsF[p] : NULL; 8570 8571 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8572 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8573 } 8574 for (p = 0, off = 0; p < numCPoints; p++) { 8575 const PetscInt *perm = permsC ? permsC[p] : NULL; 8576 8577 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8578 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8579 } 8580 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8581 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8582 } 8583 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8584 /* TODO: flips */ 8585 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8586 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8587 if (ierr) { 8588 PetscMPIInt rank; 8589 8590 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8591 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8592 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8593 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8594 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8595 } 8596 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8597 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8598 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8599 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8600 PetscFunctionReturn(PETSC_SUCCESS); 8601 } 8602 8603 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8604 { 8605 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8606 PetscInt *cpoints = NULL; 8607 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8608 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8609 DMPolytopeType ct; 8610 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8611 8612 PetscFunctionBegin; 8613 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8614 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8615 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8616 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8617 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8618 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8619 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8620 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8621 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8622 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8623 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8624 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8625 /* Column indices */ 8626 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8627 maxFPoints = numCPoints; 8628 /* Compress out points not in the section */ 8629 /* TODO: Squeeze out points with 0 dof as well */ 8630 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8631 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8632 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8633 cpoints[q * 2] = cpoints[p]; 8634 cpoints[q * 2 + 1] = cpoints[p + 1]; 8635 ++q; 8636 } 8637 } 8638 numCPoints = q; 8639 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8640 PetscInt fdof; 8641 8642 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8643 if (!dof) continue; 8644 for (f = 0; f < numFields; ++f) { 8645 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8646 coffsets[f + 1] += fdof; 8647 } 8648 numCIndices += dof; 8649 } 8650 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8651 /* Row indices */ 8652 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8653 { 8654 DMPlexTransform tr; 8655 DMPolytopeType *rct; 8656 PetscInt *rsize, *rcone, *rornt, Nt; 8657 8658 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8659 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8660 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8661 numSubcells = rsize[Nt - 1]; 8662 PetscCall(DMPlexTransformDestroy(&tr)); 8663 } 8664 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8665 for (r = 0, q = 0; r < numSubcells; ++r) { 8666 /* TODO Map from coarse to fine cells */ 8667 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8668 /* Compress out points not in the section */ 8669 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8670 for (p = 0; p < numFPoints * 2; p += 2) { 8671 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8672 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8673 if (!dof) continue; 8674 for (s = 0; s < q; ++s) 8675 if (fpoints[p] == ftotpoints[s * 2]) break; 8676 if (s < q) continue; 8677 ftotpoints[q * 2] = fpoints[p]; 8678 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8679 ++q; 8680 } 8681 } 8682 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8683 } 8684 numFPoints = q; 8685 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8686 PetscInt fdof; 8687 8688 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8689 if (!dof) continue; 8690 for (f = 0; f < numFields; ++f) { 8691 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8692 foffsets[f + 1] += fdof; 8693 } 8694 numFIndices += dof; 8695 } 8696 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8697 8698 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8699 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8700 if (numFields) { 8701 const PetscInt **permsF[32] = {NULL}; 8702 const PetscInt **permsC[32] = {NULL}; 8703 8704 for (f = 0; f < numFields; f++) { 8705 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8706 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8707 } 8708 for (p = 0; p < numFPoints; p++) { 8709 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8710 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8711 } 8712 for (p = 0; p < numCPoints; p++) { 8713 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8714 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8715 } 8716 for (f = 0; f < numFields; f++) { 8717 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8718 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8719 } 8720 } else { 8721 const PetscInt **permsF = NULL; 8722 const PetscInt **permsC = NULL; 8723 8724 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8725 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8726 for (p = 0, off = 0; p < numFPoints; p++) { 8727 const PetscInt *perm = permsF ? permsF[p] : NULL; 8728 8729 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8730 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8731 } 8732 for (p = 0, off = 0; p < numCPoints; p++) { 8733 const PetscInt *perm = permsC ? permsC[p] : NULL; 8734 8735 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8736 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8737 } 8738 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8739 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8740 } 8741 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8742 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8743 PetscFunctionReturn(PETSC_SUCCESS); 8744 } 8745 8746 /*@ 8747 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8748 8749 Input Parameter: 8750 . dm - The `DMPLEX` object 8751 8752 Output Parameter: 8753 . cellHeight - The height of a cell 8754 8755 Level: developer 8756 8757 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8758 @*/ 8759 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8760 { 8761 DM_Plex *mesh = (DM_Plex *)dm->data; 8762 8763 PetscFunctionBegin; 8764 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8765 PetscAssertPointer(cellHeight, 2); 8766 *cellHeight = mesh->vtkCellHeight; 8767 PetscFunctionReturn(PETSC_SUCCESS); 8768 } 8769 8770 /*@ 8771 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8772 8773 Input Parameters: 8774 + dm - The `DMPLEX` object 8775 - cellHeight - The height of a cell 8776 8777 Level: developer 8778 8779 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8780 @*/ 8781 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8782 { 8783 DM_Plex *mesh = (DM_Plex *)dm->data; 8784 8785 PetscFunctionBegin; 8786 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8787 mesh->vtkCellHeight = cellHeight; 8788 PetscFunctionReturn(PETSC_SUCCESS); 8789 } 8790 8791 /*@ 8792 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8793 8794 Input Parameters: 8795 + dm - The `DMPLEX` object 8796 - ct - The `DMPolytopeType` of the cell 8797 8798 Output Parameters: 8799 + start - The first cell of this type, or `NULL` 8800 - end - The upper bound on this celltype, or `NULL` 8801 8802 Level: advanced 8803 8804 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8805 @*/ 8806 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end) 8807 { 8808 DM_Plex *mesh = (DM_Plex *)dm->data; 8809 DMLabel label; 8810 PetscInt pStart, pEnd; 8811 8812 PetscFunctionBegin; 8813 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8814 if (start) { 8815 PetscAssertPointer(start, 3); 8816 *start = 0; 8817 } 8818 if (end) { 8819 PetscAssertPointer(end, 4); 8820 *end = 0; 8821 } 8822 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8823 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8824 if (mesh->tr) { 8825 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8826 } else { 8827 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8828 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8829 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8830 } 8831 PetscFunctionReturn(PETSC_SUCCESS); 8832 } 8833 8834 /*@ 8835 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8836 8837 Input Parameters: 8838 + dm - The `DMPLEX` object 8839 - depth - The depth for the given point stratum 8840 8841 Output Parameter: 8842 . gsize - The global number of points in the stratum 8843 8844 Level: advanced 8845 8846 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8847 @*/ 8848 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8849 { 8850 PetscSF sf; 8851 const PetscInt *leaves; 8852 PetscInt Nl, loc, start, end, lsize = 0; 8853 8854 PetscFunctionBegin; 8855 PetscCall(DMGetPointSF(dm, &sf)); 8856 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8857 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8858 for (PetscInt p = start; p < end; ++p) { 8859 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8860 if (loc < 0) ++lsize; 8861 } 8862 PetscCallMPI(MPI_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8863 PetscFunctionReturn(PETSC_SUCCESS); 8864 } 8865 8866 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8867 { 8868 PetscSection section, globalSection; 8869 PetscInt *numbers, p; 8870 8871 PetscFunctionBegin; 8872 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8873 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8874 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8875 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8876 PetscCall(PetscSectionSetUp(section)); 8877 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8878 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8879 for (p = pStart; p < pEnd; ++p) { 8880 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8881 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8882 else numbers[p - pStart] += shift; 8883 } 8884 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8885 if (globalSize) { 8886 PetscLayout layout; 8887 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8888 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8889 PetscCall(PetscLayoutDestroy(&layout)); 8890 } 8891 PetscCall(PetscSectionDestroy(§ion)); 8892 PetscCall(PetscSectionDestroy(&globalSection)); 8893 PetscFunctionReturn(PETSC_SUCCESS); 8894 } 8895 8896 /*@ 8897 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8898 8899 Input Parameters: 8900 + dm - The `DMPLEX` object 8901 - includeAll - Whether to include all cells, or just the simplex and box cells 8902 8903 Output Parameter: 8904 . globalCellNumbers - Global cell numbers for all cells on this process 8905 8906 Level: developer 8907 8908 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8909 @*/ 8910 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8911 { 8912 PetscInt cellHeight, cStart, cEnd; 8913 8914 PetscFunctionBegin; 8915 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8916 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8917 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8918 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8919 PetscFunctionReturn(PETSC_SUCCESS); 8920 } 8921 8922 /*@ 8923 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8924 8925 Input Parameter: 8926 . dm - The `DMPLEX` object 8927 8928 Output Parameter: 8929 . globalCellNumbers - Global cell numbers for all cells on this process 8930 8931 Level: developer 8932 8933 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8934 @*/ 8935 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8936 { 8937 DM_Plex *mesh = (DM_Plex *)dm->data; 8938 8939 PetscFunctionBegin; 8940 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8941 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8942 *globalCellNumbers = mesh->globalCellNumbers; 8943 PetscFunctionReturn(PETSC_SUCCESS); 8944 } 8945 8946 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8947 { 8948 PetscInt vStart, vEnd; 8949 8950 PetscFunctionBegin; 8951 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8952 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8953 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8954 PetscFunctionReturn(PETSC_SUCCESS); 8955 } 8956 8957 /*@ 8958 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8959 8960 Input Parameter: 8961 . dm - The `DMPLEX` object 8962 8963 Output Parameter: 8964 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8965 8966 Level: developer 8967 8968 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8969 @*/ 8970 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8971 { 8972 DM_Plex *mesh = (DM_Plex *)dm->data; 8973 8974 PetscFunctionBegin; 8975 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8976 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8977 *globalVertexNumbers = mesh->globalVertexNumbers; 8978 PetscFunctionReturn(PETSC_SUCCESS); 8979 } 8980 8981 /*@ 8982 DMPlexCreatePointNumbering - Create a global numbering for all points. 8983 8984 Collective 8985 8986 Input Parameter: 8987 . dm - The `DMPLEX` object 8988 8989 Output Parameter: 8990 . globalPointNumbers - Global numbers for all points on this process 8991 8992 Level: developer 8993 8994 Notes: 8995 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8996 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8997 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8998 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8999 9000 The partitioned mesh is 9001 ``` 9002 (2)--0--(3)--1--(4) (1)--0--(2) 9003 ``` 9004 and its global numbering is 9005 ``` 9006 (3)--0--(4)--1--(5)--2--(6) 9007 ``` 9008 Then the global numbering is provided as 9009 ``` 9010 [0] Number of indices in set 5 9011 [0] 0 0 9012 [0] 1 1 9013 [0] 2 3 9014 [0] 3 4 9015 [0] 4 -6 9016 [1] Number of indices in set 3 9017 [1] 0 2 9018 [1] 1 5 9019 [1] 2 6 9020 ``` 9021 9022 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9023 @*/ 9024 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 9025 { 9026 IS nums[4]; 9027 PetscInt depths[4], gdepths[4], starts[4]; 9028 PetscInt depth, d, shift = 0; 9029 PetscBool empty = PETSC_FALSE; 9030 9031 PetscFunctionBegin; 9032 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9033 PetscCall(DMPlexGetDepth(dm, &depth)); 9034 // For unstratified meshes use dim instead of depth 9035 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9036 // If any stratum is empty, we must mark all empty 9037 for (d = 0; d <= depth; ++d) { 9038 PetscInt end; 9039 9040 depths[d] = depth - d; 9041 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9042 if (!(starts[d] - end)) empty = PETSC_TRUE; 9043 } 9044 if (empty) 9045 for (d = 0; d <= depth; ++d) { 9046 depths[d] = -1; 9047 starts[d] = -1; 9048 } 9049 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9050 PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9051 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]); 9052 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9053 for (d = 0; d <= depth; ++d) { 9054 PetscInt pStart, pEnd, gsize; 9055 9056 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9057 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9058 shift += gsize; 9059 } 9060 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9061 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9062 PetscFunctionReturn(PETSC_SUCCESS); 9063 } 9064 9065 /*@ 9066 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9067 9068 Collective 9069 9070 Input Parameter: 9071 . dm - The `DMPLEX` object 9072 9073 Output Parameter: 9074 . globalEdgeNumbers - Global numbers for all edges on this process 9075 9076 Level: developer 9077 9078 Notes: 9079 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). 9080 9081 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9082 @*/ 9083 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9084 { 9085 PetscSF sf; 9086 PetscInt eStart, eEnd; 9087 9088 PetscFunctionBegin; 9089 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9090 PetscCall(DMGetPointSF(dm, &sf)); 9091 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9092 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9093 PetscFunctionReturn(PETSC_SUCCESS); 9094 } 9095 9096 /*@ 9097 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9098 9099 Input Parameter: 9100 . dm - The `DMPLEX` object 9101 9102 Output Parameter: 9103 . ranks - The rank field 9104 9105 Options Database Key: 9106 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9107 9108 Level: intermediate 9109 9110 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9111 @*/ 9112 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9113 { 9114 DM rdm; 9115 PetscFE fe; 9116 PetscScalar *r; 9117 PetscMPIInt rank; 9118 DMPolytopeType ct; 9119 PetscInt dim, cStart, cEnd, c; 9120 PetscBool simplex; 9121 9122 PetscFunctionBeginUser; 9123 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9124 PetscAssertPointer(ranks, 2); 9125 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9126 PetscCall(DMClone(dm, &rdm)); 9127 PetscCall(DMGetDimension(rdm, &dim)); 9128 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9129 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9130 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9131 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9132 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9133 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9134 PetscCall(PetscFEDestroy(&fe)); 9135 PetscCall(DMCreateDS(rdm)); 9136 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9137 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9138 PetscCall(VecGetArray(*ranks, &r)); 9139 for (c = cStart; c < cEnd; ++c) { 9140 PetscScalar *lr; 9141 9142 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9143 if (lr) *lr = rank; 9144 } 9145 PetscCall(VecRestoreArray(*ranks, &r)); 9146 PetscCall(DMDestroy(&rdm)); 9147 PetscFunctionReturn(PETSC_SUCCESS); 9148 } 9149 9150 /*@ 9151 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9152 9153 Input Parameters: 9154 + dm - The `DMPLEX` 9155 - label - The `DMLabel` 9156 9157 Output Parameter: 9158 . val - The label value field 9159 9160 Options Database Key: 9161 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9162 9163 Level: intermediate 9164 9165 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9166 @*/ 9167 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9168 { 9169 DM rdm, plex; 9170 Vec lval; 9171 PetscSection section; 9172 PetscFE fe; 9173 PetscScalar *v; 9174 PetscInt dim, pStart, pEnd, p, cStart; 9175 DMPolytopeType ct; 9176 char name[PETSC_MAX_PATH_LEN]; 9177 const char *lname, *prefix; 9178 9179 PetscFunctionBeginUser; 9180 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9181 PetscAssertPointer(label, 2); 9182 PetscAssertPointer(val, 3); 9183 PetscCall(DMClone(dm, &rdm)); 9184 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9185 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9186 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9187 PetscCall(DMDestroy(&plex)); 9188 PetscCall(DMGetDimension(rdm, &dim)); 9189 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9190 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9191 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9192 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9193 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9194 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9195 PetscCall(PetscFEDestroy(&fe)); 9196 PetscCall(DMCreateDS(rdm)); 9197 PetscCall(DMCreateGlobalVector(rdm, val)); 9198 PetscCall(DMCreateLocalVector(rdm, &lval)); 9199 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9200 PetscCall(DMGetLocalSection(rdm, §ion)); 9201 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9202 PetscCall(VecGetArray(lval, &v)); 9203 for (p = pStart; p < pEnd; ++p) { 9204 PetscInt cval, dof, off; 9205 9206 PetscCall(PetscSectionGetDof(section, p, &dof)); 9207 if (!dof) continue; 9208 PetscCall(DMLabelGetValue(label, p, &cval)); 9209 PetscCall(PetscSectionGetOffset(section, p, &off)); 9210 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9211 } 9212 PetscCall(VecRestoreArray(lval, &v)); 9213 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9214 PetscCall(VecDestroy(&lval)); 9215 PetscCall(DMDestroy(&rdm)); 9216 PetscFunctionReturn(PETSC_SUCCESS); 9217 } 9218 9219 /*@ 9220 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9221 9222 Input Parameter: 9223 . dm - The `DMPLEX` object 9224 9225 Level: developer 9226 9227 Notes: 9228 This is a useful diagnostic when creating meshes programmatically. 9229 9230 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9231 9232 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9233 @*/ 9234 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9235 { 9236 PetscSection coneSection, supportSection; 9237 const PetscInt *cone, *support; 9238 PetscInt coneSize, c, supportSize, s; 9239 PetscInt pStart, pEnd, p, pp, csize, ssize; 9240 PetscBool storagecheck = PETSC_TRUE; 9241 9242 PetscFunctionBegin; 9243 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9244 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9245 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9246 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9247 /* Check that point p is found in the support of its cone points, and vice versa */ 9248 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9249 for (p = pStart; p < pEnd; ++p) { 9250 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9251 PetscCall(DMPlexGetCone(dm, p, &cone)); 9252 for (c = 0; c < coneSize; ++c) { 9253 PetscBool dup = PETSC_FALSE; 9254 PetscInt d; 9255 for (d = c - 1; d >= 0; --d) { 9256 if (cone[c] == cone[d]) { 9257 dup = PETSC_TRUE; 9258 break; 9259 } 9260 } 9261 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9262 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9263 for (s = 0; s < supportSize; ++s) { 9264 if (support[s] == p) break; 9265 } 9266 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9267 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9268 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9269 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9270 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9271 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9272 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9273 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]); 9274 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9275 } 9276 } 9277 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9278 if (p != pp) { 9279 storagecheck = PETSC_FALSE; 9280 continue; 9281 } 9282 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9283 PetscCall(DMPlexGetSupport(dm, p, &support)); 9284 for (s = 0; s < supportSize; ++s) { 9285 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9286 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9287 for (c = 0; c < coneSize; ++c) { 9288 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9289 if (cone[c] != pp) { 9290 c = 0; 9291 break; 9292 } 9293 if (cone[c] == p) break; 9294 } 9295 if (c >= coneSize) { 9296 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9297 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9298 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9299 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9300 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9301 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9302 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9303 } 9304 } 9305 } 9306 if (storagecheck) { 9307 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9308 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9309 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9310 } 9311 PetscFunctionReturn(PETSC_SUCCESS); 9312 } 9313 9314 /* 9315 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. 9316 */ 9317 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9318 { 9319 DMPolytopeType cct; 9320 PetscInt ptpoints[4]; 9321 const PetscInt *cone, *ccone, *ptcone; 9322 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9323 9324 PetscFunctionBegin; 9325 *unsplit = 0; 9326 switch (ct) { 9327 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9328 ptpoints[npt++] = c; 9329 break; 9330 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9331 PetscCall(DMPlexGetCone(dm, c, &cone)); 9332 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9333 for (cp = 0; cp < coneSize; ++cp) { 9334 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9335 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9336 } 9337 break; 9338 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9339 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9340 PetscCall(DMPlexGetCone(dm, c, &cone)); 9341 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9342 for (cp = 0; cp < coneSize; ++cp) { 9343 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9344 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9345 for (ccp = 0; ccp < cconeSize; ++ccp) { 9346 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9347 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9348 PetscInt p; 9349 for (p = 0; p < npt; ++p) 9350 if (ptpoints[p] == ccone[ccp]) break; 9351 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9352 } 9353 } 9354 } 9355 break; 9356 default: 9357 break; 9358 } 9359 for (pt = 0; pt < npt; ++pt) { 9360 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9361 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9362 } 9363 PetscFunctionReturn(PETSC_SUCCESS); 9364 } 9365 9366 /*@ 9367 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9368 9369 Input Parameters: 9370 + dm - The `DMPLEX` object 9371 - cellHeight - Normally 0 9372 9373 Level: developer 9374 9375 Notes: 9376 This is a useful diagnostic when creating meshes programmatically. 9377 Currently applicable only to homogeneous simplex or tensor meshes. 9378 9379 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9380 9381 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9382 @*/ 9383 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9384 { 9385 DMPlexInterpolatedFlag interp; 9386 DMPolytopeType ct; 9387 PetscInt vStart, vEnd, cStart, cEnd, c; 9388 9389 PetscFunctionBegin; 9390 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9391 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9392 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9393 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9394 for (c = cStart; c < cEnd; ++c) { 9395 PetscInt *closure = NULL; 9396 PetscInt coneSize, closureSize, cl, Nv = 0; 9397 9398 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9399 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9400 if (interp == DMPLEX_INTERPOLATED_FULL) { 9401 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9402 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)); 9403 } 9404 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9405 for (cl = 0; cl < closureSize * 2; cl += 2) { 9406 const PetscInt p = closure[cl]; 9407 if ((p >= vStart) && (p < vEnd)) ++Nv; 9408 } 9409 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9410 /* Special Case: Tensor faces with identified vertices */ 9411 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9412 PetscInt unsplit; 9413 9414 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9415 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9416 } 9417 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)); 9418 } 9419 PetscFunctionReturn(PETSC_SUCCESS); 9420 } 9421 9422 /*@ 9423 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9424 9425 Collective 9426 9427 Input Parameters: 9428 + dm - The `DMPLEX` object 9429 - cellHeight - Normally 0 9430 9431 Level: developer 9432 9433 Notes: 9434 This is a useful diagnostic when creating meshes programmatically. 9435 This routine is only relevant for meshes that are fully interpolated across all ranks. 9436 It will error out if a partially interpolated mesh is given on some rank. 9437 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9438 9439 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9440 9441 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9442 @*/ 9443 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9444 { 9445 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9446 DMPlexInterpolatedFlag interpEnum; 9447 9448 PetscFunctionBegin; 9449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9450 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9451 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9452 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9453 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9454 PetscFunctionReturn(PETSC_SUCCESS); 9455 } 9456 9457 PetscCall(DMGetDimension(dm, &dim)); 9458 PetscCall(DMPlexGetDepth(dm, &depth)); 9459 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9460 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9461 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9462 for (c = cStart; c < cEnd; ++c) { 9463 const PetscInt *cone, *ornt, *faceSizes, *faces; 9464 const DMPolytopeType *faceTypes; 9465 DMPolytopeType ct; 9466 PetscInt numFaces, coneSize, f; 9467 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9468 9469 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9470 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9471 if (unsplit) continue; 9472 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9473 PetscCall(DMPlexGetCone(dm, c, &cone)); 9474 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9475 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9476 for (cl = 0; cl < closureSize * 2; cl += 2) { 9477 const PetscInt p = closure[cl]; 9478 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9479 } 9480 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9481 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); 9482 for (f = 0; f < numFaces; ++f) { 9483 DMPolytopeType fct; 9484 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9485 9486 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9487 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9488 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9489 const PetscInt p = fclosure[cl]; 9490 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9491 } 9492 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]); 9493 for (v = 0; v < fnumCorners; ++v) { 9494 if (fclosure[v] != faces[fOff + v]) { 9495 PetscInt v1; 9496 9497 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9498 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9499 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9500 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9501 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9502 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]); 9503 } 9504 } 9505 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9506 fOff += faceSizes[f]; 9507 } 9508 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9509 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9510 } 9511 } 9512 PetscFunctionReturn(PETSC_SUCCESS); 9513 } 9514 9515 /*@ 9516 DMPlexCheckGeometry - Check the geometry of mesh cells 9517 9518 Input Parameter: 9519 . dm - The `DMPLEX` object 9520 9521 Level: developer 9522 9523 Notes: 9524 This is a useful diagnostic when creating meshes programmatically. 9525 9526 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9527 9528 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9529 @*/ 9530 PetscErrorCode DMPlexCheckGeometry(DM dm) 9531 { 9532 Vec coordinates; 9533 PetscReal detJ, J[9], refVol = 1.0; 9534 PetscReal vol; 9535 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9536 9537 PetscFunctionBegin; 9538 PetscCall(DMGetDimension(dm, &dim)); 9539 PetscCall(DMGetCoordinateDim(dm, &dE)); 9540 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9541 PetscCall(DMPlexGetDepth(dm, &depth)); 9542 for (d = 0; d < dim; ++d) refVol *= 2.0; 9543 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9544 /* Make sure local coordinates are created, because that step is collective */ 9545 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9546 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9547 for (c = cStart; c < cEnd; ++c) { 9548 DMPolytopeType ct; 9549 PetscInt unsplit; 9550 PetscBool ignoreZeroVol = PETSC_FALSE; 9551 9552 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9553 switch (ct) { 9554 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9555 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9556 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9557 ignoreZeroVol = PETSC_TRUE; 9558 break; 9559 default: 9560 break; 9561 } 9562 switch (ct) { 9563 case DM_POLYTOPE_TRI_PRISM: 9564 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9565 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9566 case DM_POLYTOPE_PYRAMID: 9567 continue; 9568 default: 9569 break; 9570 } 9571 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9572 if (unsplit) continue; 9573 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9574 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); 9575 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9576 /* This should work with periodicity since DG coordinates should be used */ 9577 if (depth > 1) { 9578 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9579 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); 9580 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9581 } 9582 } 9583 PetscFunctionReturn(PETSC_SUCCESS); 9584 } 9585 9586 /*@ 9587 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9588 9589 Collective 9590 9591 Input Parameters: 9592 + dm - The `DMPLEX` object 9593 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9594 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9595 9596 Level: developer 9597 9598 Notes: 9599 This is mainly intended for debugging/testing purposes. 9600 9601 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9602 9603 Extra roots can come from periodic cuts, where additional points appear on the boundary 9604 9605 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9606 @*/ 9607 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9608 { 9609 PetscInt l, nleaves, nroots, overlap; 9610 const PetscInt *locals; 9611 const PetscSFNode *remotes; 9612 PetscBool distributed; 9613 MPI_Comm comm; 9614 PetscMPIInt rank; 9615 9616 PetscFunctionBegin; 9617 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9618 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9619 else pointSF = dm->sf; 9620 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9621 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9622 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9623 { 9624 PetscMPIInt mpiFlag; 9625 9626 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9627 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9628 } 9629 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9630 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9631 if (!distributed) { 9632 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); 9633 PetscFunctionReturn(PETSC_SUCCESS); 9634 } 9635 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); 9636 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9637 9638 /* Check SF graph is compatible with DMPlex chart */ 9639 { 9640 PetscInt pStart, pEnd, maxLeaf; 9641 9642 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9643 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9644 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9645 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9646 } 9647 9648 /* Check there are no cells in interface */ 9649 if (!overlap) { 9650 PetscInt cellHeight, cStart, cEnd; 9651 9652 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9653 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9654 for (l = 0; l < nleaves; ++l) { 9655 const PetscInt point = locals ? locals[l] : l; 9656 9657 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9658 } 9659 } 9660 9661 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9662 { 9663 const PetscInt *rootdegree; 9664 9665 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9666 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9667 for (l = 0; l < nleaves; ++l) { 9668 const PetscInt point = locals ? locals[l] : l; 9669 const PetscInt *cone; 9670 PetscInt coneSize, c, idx; 9671 9672 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9673 PetscCall(DMPlexGetCone(dm, point, &cone)); 9674 for (c = 0; c < coneSize; ++c) { 9675 if (!rootdegree[cone[c]]) { 9676 if (locals) { 9677 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9678 } else { 9679 idx = (cone[c] < nleaves) ? cone[c] : -1; 9680 } 9681 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9682 } 9683 } 9684 } 9685 } 9686 PetscFunctionReturn(PETSC_SUCCESS); 9687 } 9688 9689 /*@ 9690 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9691 9692 Collective 9693 9694 Input Parameter: 9695 . dm - The `DMPLEX` object 9696 9697 Level: developer 9698 9699 Notes: 9700 This is mainly intended for debugging/testing purposes. 9701 9702 Other cell types which are disconnected would be caught by the symmetry and face checks. 9703 9704 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9705 9706 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9707 @*/ 9708 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9709 { 9710 PetscInt pStart, pEnd, vStart, vEnd; 9711 9712 PetscFunctionBegin; 9713 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9714 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9715 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9716 for (PetscInt v = vStart; v < vEnd; ++v) { 9717 PetscInt suppSize; 9718 9719 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9720 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9721 } 9722 PetscFunctionReturn(PETSC_SUCCESS); 9723 } 9724 9725 /*@ 9726 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9727 9728 Input Parameter: 9729 . dm - The `DMPLEX` object 9730 9731 Level: developer 9732 9733 Notes: 9734 This is a useful diagnostic when creating meshes programmatically. 9735 9736 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9737 9738 Currently does not include `DMPlexCheckCellShape()`. 9739 9740 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9741 @*/ 9742 PetscErrorCode DMPlexCheck(DM dm) 9743 { 9744 PetscInt cellHeight; 9745 9746 PetscFunctionBegin; 9747 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9748 PetscCall(DMPlexCheckSymmetry(dm)); 9749 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9750 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9751 PetscCall(DMPlexCheckGeometry(dm)); 9752 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9753 PetscCall(DMPlexCheckInterfaceCones(dm)); 9754 PetscCall(DMPlexCheckOrphanVertices(dm)); 9755 PetscFunctionReturn(PETSC_SUCCESS); 9756 } 9757 9758 typedef struct cell_stats { 9759 PetscReal min, max, sum, squaresum; 9760 PetscInt count; 9761 } cell_stats_t; 9762 9763 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9764 { 9765 PetscInt i, N = *len; 9766 9767 for (i = 0; i < N; i++) { 9768 cell_stats_t *A = (cell_stats_t *)a; 9769 cell_stats_t *B = (cell_stats_t *)b; 9770 9771 B->min = PetscMin(A->min, B->min); 9772 B->max = PetscMax(A->max, B->max); 9773 B->sum += A->sum; 9774 B->squaresum += A->squaresum; 9775 B->count += A->count; 9776 } 9777 } 9778 9779 /*@ 9780 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9781 9782 Collective 9783 9784 Input Parameters: 9785 + dm - The `DMPLEX` object 9786 . output - If true, statistics will be displayed on `stdout` 9787 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9788 9789 Level: developer 9790 9791 Notes: 9792 This is mainly intended for debugging/testing purposes. 9793 9794 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9795 9796 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9797 @*/ 9798 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9799 { 9800 DM dmCoarse; 9801 cell_stats_t stats, globalStats; 9802 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9803 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9804 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9805 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9806 PetscMPIInt rank, size; 9807 9808 PetscFunctionBegin; 9809 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9810 stats.min = PETSC_MAX_REAL; 9811 stats.max = PETSC_MIN_REAL; 9812 stats.sum = stats.squaresum = 0.; 9813 stats.count = 0; 9814 9815 PetscCallMPI(MPI_Comm_size(comm, &size)); 9816 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9817 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9818 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9819 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9820 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9821 for (c = cStart; c < cEnd; c++) { 9822 PetscInt i; 9823 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9824 9825 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9826 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9827 for (i = 0; i < PetscSqr(cdim); ++i) { 9828 frobJ += J[i] * J[i]; 9829 frobInvJ += invJ[i] * invJ[i]; 9830 } 9831 cond2 = frobJ * frobInvJ; 9832 cond = PetscSqrtReal(cond2); 9833 9834 stats.min = PetscMin(stats.min, cond); 9835 stats.max = PetscMax(stats.max, cond); 9836 stats.sum += cond; 9837 stats.squaresum += cond2; 9838 stats.count++; 9839 if (output && cond > limit) { 9840 PetscSection coordSection; 9841 Vec coordsLocal; 9842 PetscScalar *coords = NULL; 9843 PetscInt Nv, d, clSize, cl, *closure = NULL; 9844 9845 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9846 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9847 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9848 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9849 for (i = 0; i < Nv / cdim; ++i) { 9850 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9851 for (d = 0; d < cdim; ++d) { 9852 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9853 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9854 } 9855 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9856 } 9857 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9858 for (cl = 0; cl < clSize * 2; cl += 2) { 9859 const PetscInt edge = closure[cl]; 9860 9861 if ((edge >= eStart) && (edge < eEnd)) { 9862 PetscReal len; 9863 9864 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9865 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9866 } 9867 } 9868 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9869 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9870 } 9871 } 9872 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9873 9874 if (size > 1) { 9875 PetscMPIInt blockLengths[2] = {4, 1}; 9876 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9877 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9878 MPI_Op statReduce; 9879 9880 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9881 PetscCallMPI(MPI_Type_commit(&statType)); 9882 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9883 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9884 PetscCallMPI(MPI_Op_free(&statReduce)); 9885 PetscCallMPI(MPI_Type_free(&statType)); 9886 } else { 9887 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9888 } 9889 if (rank == 0) { 9890 count = globalStats.count; 9891 min = globalStats.min; 9892 max = globalStats.max; 9893 mean = globalStats.sum / globalStats.count; 9894 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9895 } 9896 9897 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)); 9898 PetscCall(PetscFree2(J, invJ)); 9899 9900 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9901 if (dmCoarse) { 9902 PetscBool isplex; 9903 9904 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9905 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9906 } 9907 PetscFunctionReturn(PETSC_SUCCESS); 9908 } 9909 9910 /*@ 9911 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9912 orthogonal quality below given tolerance. 9913 9914 Collective 9915 9916 Input Parameters: 9917 + dm - The `DMPLEX` object 9918 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9919 - atol - [0, 1] Absolute tolerance for tagging cells. 9920 9921 Output Parameters: 9922 + OrthQual - `Vec` containing orthogonal quality per cell 9923 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9924 9925 Options Database Keys: 9926 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9927 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9928 9929 Level: intermediate 9930 9931 Notes: 9932 Orthogonal quality is given by the following formula\: 9933 9934 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9935 9936 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 9937 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9938 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9939 calculating the cosine of the angle between these vectors. 9940 9941 Orthogonal quality ranges from 1 (best) to 0 (worst). 9942 9943 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9944 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9945 9946 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9947 9948 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9949 @*/ 9950 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9951 { 9952 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9953 PetscInt *idx; 9954 PetscScalar *oqVals; 9955 const PetscScalar *cellGeomArr, *faceGeomArr; 9956 PetscReal *ci, *fi, *Ai; 9957 MPI_Comm comm; 9958 Vec cellgeom, facegeom; 9959 DM dmFace, dmCell; 9960 IS glob; 9961 ISLocalToGlobalMapping ltog; 9962 PetscViewer vwr; 9963 9964 PetscFunctionBegin; 9965 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9966 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9967 PetscAssertPointer(OrthQual, 4); 9968 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9969 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9970 PetscCall(DMGetDimension(dm, &nc)); 9971 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9972 { 9973 DMPlexInterpolatedFlag interpFlag; 9974 9975 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9976 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9977 PetscMPIInt rank; 9978 9979 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9980 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9981 } 9982 } 9983 if (OrthQualLabel) { 9984 PetscAssertPointer(OrthQualLabel, 5); 9985 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9986 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9987 } else { 9988 *OrthQualLabel = NULL; 9989 } 9990 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9991 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9992 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9993 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9994 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9995 PetscCall(VecCreate(comm, OrthQual)); 9996 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9997 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9998 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9999 PetscCall(VecSetUp(*OrthQual)); 10000 PetscCall(ISDestroy(&glob)); 10001 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 10002 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 10003 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 10004 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 10005 PetscCall(VecGetDM(cellgeom, &dmCell)); 10006 PetscCall(VecGetDM(facegeom, &dmFace)); 10007 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 10008 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 10009 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 10010 PetscInt cellarr[2], *adj = NULL; 10011 PetscScalar *cArr, *fArr; 10012 PetscReal minvalc = 1.0, minvalf = 1.0; 10013 PetscFVCellGeom *cg; 10014 10015 idx[cellIter] = cell - cStart; 10016 cellarr[0] = cell; 10017 /* Make indexing into cellGeom easier */ 10018 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10019 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10020 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10021 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10022 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10023 PetscInt i; 10024 const PetscInt neigh = adj[cellneigh]; 10025 PetscReal normci = 0, normfi = 0, normai = 0; 10026 PetscFVCellGeom *cgneigh; 10027 PetscFVFaceGeom *fg; 10028 10029 /* Don't count ourselves in the neighbor list */ 10030 if (neigh == cell) continue; 10031 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10032 cellarr[1] = neigh; 10033 { 10034 PetscInt numcovpts; 10035 const PetscInt *covpts; 10036 10037 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10038 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10039 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10040 } 10041 10042 /* Compute c_i, f_i and their norms */ 10043 for (i = 0; i < nc; i++) { 10044 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10045 fi[i] = fg->centroid[i] - cg->centroid[i]; 10046 Ai[i] = fg->normal[i]; 10047 normci += PetscPowReal(ci[i], 2); 10048 normfi += PetscPowReal(fi[i], 2); 10049 normai += PetscPowReal(Ai[i], 2); 10050 } 10051 normci = PetscSqrtReal(normci); 10052 normfi = PetscSqrtReal(normfi); 10053 normai = PetscSqrtReal(normai); 10054 10055 /* Normalize and compute for each face-cell-normal pair */ 10056 for (i = 0; i < nc; i++) { 10057 ci[i] = ci[i] / normci; 10058 fi[i] = fi[i] / normfi; 10059 Ai[i] = Ai[i] / normai; 10060 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10061 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10062 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10063 } 10064 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10065 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10066 } 10067 PetscCall(PetscFree(adj)); 10068 PetscCall(PetscFree2(cArr, fArr)); 10069 /* Defer to cell if they're equal */ 10070 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10071 if (OrthQualLabel) { 10072 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10073 } 10074 } 10075 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10076 PetscCall(VecAssemblyBegin(*OrthQual)); 10077 PetscCall(VecAssemblyEnd(*OrthQual)); 10078 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10079 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10080 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10081 if (OrthQualLabel) { 10082 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10083 } 10084 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10085 PetscCall(PetscViewerDestroy(&vwr)); 10086 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10087 PetscFunctionReturn(PETSC_SUCCESS); 10088 } 10089 10090 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10091 * interpolator construction */ 10092 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10093 { 10094 PetscSection section, newSection, gsection; 10095 PetscSF sf; 10096 PetscBool hasConstraints, ghasConstraints; 10097 10098 PetscFunctionBegin; 10099 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10100 PetscAssertPointer(odm, 2); 10101 PetscCall(DMGetLocalSection(dm, §ion)); 10102 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10103 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10104 if (!ghasConstraints) { 10105 PetscCall(PetscObjectReference((PetscObject)dm)); 10106 *odm = dm; 10107 PetscFunctionReturn(PETSC_SUCCESS); 10108 } 10109 PetscCall(DMClone(dm, odm)); 10110 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10111 PetscCall(DMGetLocalSection(*odm, &newSection)); 10112 PetscCall(DMGetPointSF(*odm, &sf)); 10113 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10114 PetscCall(DMSetGlobalSection(*odm, gsection)); 10115 PetscCall(PetscSectionDestroy(&gsection)); 10116 PetscFunctionReturn(PETSC_SUCCESS); 10117 } 10118 10119 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10120 { 10121 DM dmco, dmfo; 10122 Mat interpo; 10123 Vec rscale; 10124 Vec cglobalo, clocal; 10125 Vec fglobal, fglobalo, flocal; 10126 PetscBool regular; 10127 10128 PetscFunctionBegin; 10129 PetscCall(DMGetFullDM(dmc, &dmco)); 10130 PetscCall(DMGetFullDM(dmf, &dmfo)); 10131 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10132 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10133 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10134 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10135 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10136 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10137 PetscCall(VecSet(cglobalo, 0.)); 10138 PetscCall(VecSet(clocal, 0.)); 10139 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10140 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10141 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10142 PetscCall(VecSet(fglobal, 0.)); 10143 PetscCall(VecSet(fglobalo, 0.)); 10144 PetscCall(VecSet(flocal, 0.)); 10145 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10146 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10147 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10148 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10149 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10150 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10151 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10152 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10153 *shift = fglobal; 10154 PetscCall(VecDestroy(&flocal)); 10155 PetscCall(VecDestroy(&fglobalo)); 10156 PetscCall(VecDestroy(&clocal)); 10157 PetscCall(VecDestroy(&cglobalo)); 10158 PetscCall(VecDestroy(&rscale)); 10159 PetscCall(MatDestroy(&interpo)); 10160 PetscCall(DMDestroy(&dmfo)); 10161 PetscCall(DMDestroy(&dmco)); 10162 PetscFunctionReturn(PETSC_SUCCESS); 10163 } 10164 10165 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10166 { 10167 PetscObject shifto; 10168 Vec shift; 10169 10170 PetscFunctionBegin; 10171 if (!interp) { 10172 Vec rscale; 10173 10174 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10175 PetscCall(VecDestroy(&rscale)); 10176 } else { 10177 PetscCall(PetscObjectReference((PetscObject)interp)); 10178 } 10179 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10180 if (!shifto) { 10181 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10182 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10183 shifto = (PetscObject)shift; 10184 PetscCall(VecDestroy(&shift)); 10185 } 10186 shift = (Vec)shifto; 10187 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10188 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10189 PetscCall(MatDestroy(&interp)); 10190 PetscFunctionReturn(PETSC_SUCCESS); 10191 } 10192 10193 /* Pointwise interpolation 10194 Just code FEM for now 10195 u^f = I u^c 10196 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10197 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10198 I_{ij} = psi^f_i phi^c_j 10199 */ 10200 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10201 { 10202 PetscSection gsc, gsf; 10203 PetscInt m, n; 10204 void *ctx; 10205 DM cdm; 10206 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10207 10208 PetscFunctionBegin; 10209 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10210 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10211 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10212 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10213 10214 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10215 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10216 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10217 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10218 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10219 10220 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10221 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10222 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10223 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10224 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10225 if (scaling) { 10226 /* Use naive scaling */ 10227 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10228 } 10229 PetscFunctionReturn(PETSC_SUCCESS); 10230 } 10231 10232 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10233 { 10234 VecScatter ctx; 10235 10236 PetscFunctionBegin; 10237 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10238 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10239 PetscCall(VecScatterDestroy(&ctx)); 10240 PetscFunctionReturn(PETSC_SUCCESS); 10241 } 10242 10243 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[]) 10244 { 10245 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10246 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10247 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10248 } 10249 10250 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10251 { 10252 DM dmc; 10253 PetscDS ds; 10254 Vec ones, locmass; 10255 IS cellIS; 10256 PetscFormKey key; 10257 PetscInt depth; 10258 10259 PetscFunctionBegin; 10260 PetscCall(DMClone(dm, &dmc)); 10261 PetscCall(DMCopyDisc(dm, dmc)); 10262 PetscCall(DMGetDS(dmc, &ds)); 10263 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10264 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10265 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10266 else PetscCall(DMGetLocalVector(dm, &locmass)); 10267 PetscCall(DMGetLocalVector(dm, &ones)); 10268 PetscCall(DMPlexGetDepth(dm, &depth)); 10269 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10270 PetscCall(VecSet(locmass, 0.0)); 10271 PetscCall(VecSet(ones, 1.0)); 10272 key.label = NULL; 10273 key.value = 0; 10274 key.field = 0; 10275 key.part = 0; 10276 PetscCall(DMPlexComputeJacobianActionByKey(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10277 PetscCall(ISDestroy(&cellIS)); 10278 if (mass) { 10279 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10280 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10281 } 10282 PetscCall(DMRestoreLocalVector(dm, &ones)); 10283 if (lmass) *lmass = locmass; 10284 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10285 PetscCall(DMDestroy(&dmc)); 10286 PetscFunctionReturn(PETSC_SUCCESS); 10287 } 10288 10289 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10290 { 10291 PetscSection gsc, gsf; 10292 PetscInt m, n; 10293 void *ctx; 10294 DM cdm; 10295 PetscBool regular; 10296 10297 PetscFunctionBegin; 10298 if (dmFine == dmCoarse) { 10299 DM dmc; 10300 PetscDS ds; 10301 PetscWeakForm wf; 10302 Vec u; 10303 IS cellIS; 10304 PetscFormKey key; 10305 PetscInt depth; 10306 10307 PetscCall(DMClone(dmFine, &dmc)); 10308 PetscCall(DMCopyDisc(dmFine, dmc)); 10309 PetscCall(DMGetDS(dmc, &ds)); 10310 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10311 PetscCall(PetscWeakFormClear(wf)); 10312 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10313 PetscCall(DMCreateMatrix(dmc, mass)); 10314 PetscCall(DMGetLocalVector(dmc, &u)); 10315 PetscCall(DMPlexGetDepth(dmc, &depth)); 10316 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10317 PetscCall(MatZeroEntries(*mass)); 10318 key.label = NULL; 10319 key.value = 0; 10320 key.field = 0; 10321 key.part = 0; 10322 PetscCall(DMPlexComputeJacobianByKey(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10323 PetscCall(ISDestroy(&cellIS)); 10324 PetscCall(DMRestoreLocalVector(dmc, &u)); 10325 PetscCall(DMDestroy(&dmc)); 10326 } else { 10327 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10328 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10329 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10330 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10331 10332 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10333 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10334 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10335 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10336 10337 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10338 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10339 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10340 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10341 } 10342 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10343 PetscFunctionReturn(PETSC_SUCCESS); 10344 } 10345 10346 /*@ 10347 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10348 10349 Input Parameter: 10350 . dm - The `DMPLEX` object 10351 10352 Output Parameter: 10353 . regular - The flag 10354 10355 Level: intermediate 10356 10357 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10358 @*/ 10359 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10360 { 10361 PetscFunctionBegin; 10362 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10363 PetscAssertPointer(regular, 2); 10364 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10365 PetscFunctionReturn(PETSC_SUCCESS); 10366 } 10367 10368 /*@ 10369 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10370 10371 Input Parameters: 10372 + dm - The `DMPLEX` object 10373 - regular - The flag 10374 10375 Level: intermediate 10376 10377 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10378 @*/ 10379 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10380 { 10381 PetscFunctionBegin; 10382 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10383 ((DM_Plex *)dm->data)->regularRefinement = regular; 10384 PetscFunctionReturn(PETSC_SUCCESS); 10385 } 10386 10387 /*@ 10388 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10389 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10390 10391 Not Collective 10392 10393 Input Parameter: 10394 . dm - The `DMPLEX` object 10395 10396 Output Parameters: 10397 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10398 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10399 10400 Level: intermediate 10401 10402 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10403 @*/ 10404 PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS) 10405 { 10406 DM_Plex *plex = (DM_Plex *)dm->data; 10407 10408 PetscFunctionBegin; 10409 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10410 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10411 if (anchorSection) *anchorSection = plex->anchorSection; 10412 if (anchorIS) *anchorIS = plex->anchorIS; 10413 PetscFunctionReturn(PETSC_SUCCESS); 10414 } 10415 10416 /*@ 10417 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10418 10419 Collective 10420 10421 Input Parameters: 10422 + dm - The `DMPLEX` object 10423 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10424 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10425 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10426 10427 Level: intermediate 10428 10429 Notes: 10430 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10431 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10432 combination of other points' degrees of freedom. 10433 10434 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10435 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10436 10437 The reference counts of `anchorSection` and `anchorIS` are incremented. 10438 10439 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10440 @*/ 10441 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10442 { 10443 DM_Plex *plex = (DM_Plex *)dm->data; 10444 PetscMPIInt result; 10445 10446 PetscFunctionBegin; 10447 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10448 if (anchorSection) { 10449 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10450 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10451 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10452 } 10453 if (anchorIS) { 10454 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10455 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10456 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10457 } 10458 10459 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10460 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10461 plex->anchorSection = anchorSection; 10462 10463 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10464 PetscCall(ISDestroy(&plex->anchorIS)); 10465 plex->anchorIS = anchorIS; 10466 10467 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10468 PetscInt size, a, pStart, pEnd; 10469 const PetscInt *anchors; 10470 10471 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10472 PetscCall(ISGetLocalSize(anchorIS, &size)); 10473 PetscCall(ISGetIndices(anchorIS, &anchors)); 10474 for (a = 0; a < size; a++) { 10475 PetscInt p; 10476 10477 p = anchors[a]; 10478 if (p >= pStart && p < pEnd) { 10479 PetscInt dof; 10480 10481 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10482 if (dof) { 10483 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10484 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10485 } 10486 } 10487 } 10488 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10489 } 10490 /* reset the generic constraints */ 10491 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10492 PetscFunctionReturn(PETSC_SUCCESS); 10493 } 10494 10495 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10496 { 10497 PetscSection anchorSection; 10498 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10499 10500 PetscFunctionBegin; 10501 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10502 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10503 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10504 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10505 if (numFields) { 10506 PetscInt f; 10507 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10508 10509 for (f = 0; f < numFields; f++) { 10510 PetscInt numComp; 10511 10512 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10513 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10514 } 10515 } 10516 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10517 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10518 pStart = PetscMax(pStart, sStart); 10519 pEnd = PetscMin(pEnd, sEnd); 10520 pEnd = PetscMax(pStart, pEnd); 10521 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10522 for (p = pStart; p < pEnd; p++) { 10523 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10524 if (dof) { 10525 PetscCall(PetscSectionGetDof(section, p, &dof)); 10526 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10527 for (f = 0; f < numFields; f++) { 10528 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10529 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10530 } 10531 } 10532 } 10533 PetscCall(PetscSectionSetUp(*cSec)); 10534 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10535 PetscFunctionReturn(PETSC_SUCCESS); 10536 } 10537 10538 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10539 { 10540 PetscSection aSec; 10541 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10542 const PetscInt *anchors; 10543 PetscInt numFields, f; 10544 IS aIS; 10545 MatType mtype; 10546 PetscBool iscuda, iskokkos; 10547 10548 PetscFunctionBegin; 10549 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10550 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10551 PetscCall(PetscSectionGetStorageSize(section, &n)); 10552 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10553 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10554 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10555 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10556 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10557 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10558 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10559 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10560 else mtype = MATSEQAIJ; 10561 PetscCall(MatSetType(*cMat, mtype)); 10562 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10563 PetscCall(ISGetIndices(aIS, &anchors)); 10564 /* cSec will be a subset of aSec and section */ 10565 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10566 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10567 PetscCall(PetscMalloc1(m + 1, &i)); 10568 i[0] = 0; 10569 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10570 for (p = pStart; p < pEnd; p++) { 10571 PetscInt rDof, rOff, r; 10572 10573 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10574 if (!rDof) continue; 10575 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10576 if (numFields) { 10577 for (f = 0; f < numFields; f++) { 10578 annz = 0; 10579 for (r = 0; r < rDof; r++) { 10580 a = anchors[rOff + r]; 10581 if (a < sStart || a >= sEnd) continue; 10582 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10583 annz += aDof; 10584 } 10585 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10586 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10587 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10588 } 10589 } else { 10590 annz = 0; 10591 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10592 for (q = 0; q < dof; q++) { 10593 a = anchors[rOff + q]; 10594 if (a < sStart || a >= sEnd) continue; 10595 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10596 annz += aDof; 10597 } 10598 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10599 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10600 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10601 } 10602 } 10603 nnz = i[m]; 10604 PetscCall(PetscMalloc1(nnz, &j)); 10605 offset = 0; 10606 for (p = pStart; p < pEnd; p++) { 10607 if (numFields) { 10608 for (f = 0; f < numFields; f++) { 10609 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10610 for (q = 0; q < dof; q++) { 10611 PetscInt rDof, rOff, r; 10612 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10613 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10614 for (r = 0; r < rDof; r++) { 10615 PetscInt s; 10616 10617 a = anchors[rOff + r]; 10618 if (a < sStart || a >= sEnd) continue; 10619 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10620 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10621 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10622 } 10623 } 10624 } 10625 } else { 10626 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10627 for (q = 0; q < dof; q++) { 10628 PetscInt rDof, rOff, r; 10629 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10630 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10631 for (r = 0; r < rDof; r++) { 10632 PetscInt s; 10633 10634 a = anchors[rOff + r]; 10635 if (a < sStart || a >= sEnd) continue; 10636 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10637 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10638 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10639 } 10640 } 10641 } 10642 } 10643 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10644 PetscCall(PetscFree(i)); 10645 PetscCall(PetscFree(j)); 10646 PetscCall(ISRestoreIndices(aIS, &anchors)); 10647 PetscFunctionReturn(PETSC_SUCCESS); 10648 } 10649 10650 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10651 { 10652 DM_Plex *plex = (DM_Plex *)dm->data; 10653 PetscSection anchorSection, section, cSec; 10654 Mat cMat; 10655 10656 PetscFunctionBegin; 10657 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10658 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10659 if (anchorSection) { 10660 PetscInt Nf; 10661 10662 PetscCall(DMGetLocalSection(dm, §ion)); 10663 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10664 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10665 PetscCall(DMGetNumFields(dm, &Nf)); 10666 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10667 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10668 PetscCall(PetscSectionDestroy(&cSec)); 10669 PetscCall(MatDestroy(&cMat)); 10670 } 10671 PetscFunctionReturn(PETSC_SUCCESS); 10672 } 10673 10674 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10675 { 10676 IS subis; 10677 PetscSection section, subsection; 10678 10679 PetscFunctionBegin; 10680 PetscCall(DMGetLocalSection(dm, §ion)); 10681 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10682 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10683 /* Create subdomain */ 10684 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10685 /* Create submodel */ 10686 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10687 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10688 PetscCall(DMSetLocalSection(*subdm, subsection)); 10689 PetscCall(PetscSectionDestroy(&subsection)); 10690 PetscCall(DMCopyDisc(dm, *subdm)); 10691 /* Create map from submodel to global model */ 10692 if (is) { 10693 PetscSection sectionGlobal, subsectionGlobal; 10694 IS spIS; 10695 const PetscInt *spmap; 10696 PetscInt *subIndices; 10697 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10698 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10699 10700 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10701 PetscCall(ISGetIndices(spIS, &spmap)); 10702 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10703 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10704 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10705 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10706 for (p = pStart; p < pEnd; ++p) { 10707 PetscInt gdof, pSubSize = 0; 10708 10709 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10710 if (gdof > 0) { 10711 for (f = 0; f < Nf; ++f) { 10712 PetscInt fdof, fcdof; 10713 10714 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10715 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10716 pSubSize += fdof - fcdof; 10717 } 10718 subSize += pSubSize; 10719 if (pSubSize) { 10720 if (bs < 0) { 10721 bs = pSubSize; 10722 } else if (bs != pSubSize) { 10723 /* Layout does not admit a pointwise block size */ 10724 bs = 1; 10725 } 10726 } 10727 } 10728 } 10729 /* Must have same blocksize on all procs (some might have no points) */ 10730 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10731 bsLocal[1] = bs; 10732 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10733 if (bsMinMax[0] != bsMinMax[1]) { 10734 bs = 1; 10735 } else { 10736 bs = bsMinMax[0]; 10737 } 10738 PetscCall(PetscMalloc1(subSize, &subIndices)); 10739 for (p = pStart; p < pEnd; ++p) { 10740 PetscInt gdof, goff; 10741 10742 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10743 if (gdof > 0) { 10744 const PetscInt point = spmap[p]; 10745 10746 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10747 for (f = 0; f < Nf; ++f) { 10748 PetscInt fdof, fcdof, fc, f2, poff = 0; 10749 10750 /* Can get rid of this loop by storing field information in the global section */ 10751 for (f2 = 0; f2 < f; ++f2) { 10752 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10753 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10754 poff += fdof - fcdof; 10755 } 10756 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10757 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10758 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10759 } 10760 } 10761 } 10762 PetscCall(ISRestoreIndices(spIS, &spmap)); 10763 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10764 if (bs > 1) { 10765 /* We need to check that the block size does not come from non-contiguous fields */ 10766 PetscInt i, j, set = 1; 10767 for (i = 0; i < subSize; i += bs) { 10768 for (j = 0; j < bs; ++j) { 10769 if (subIndices[i + j] != subIndices[i] + j) { 10770 set = 0; 10771 break; 10772 } 10773 } 10774 } 10775 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10776 } 10777 /* Attach nullspace */ 10778 for (f = 0; f < Nf; ++f) { 10779 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10780 if ((*subdm)->nullspaceConstructors[f]) break; 10781 } 10782 if (f < Nf) { 10783 MatNullSpace nullSpace; 10784 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10785 10786 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10787 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10788 } 10789 } 10790 PetscFunctionReturn(PETSC_SUCCESS); 10791 } 10792 10793 /*@ 10794 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10795 10796 Input Parameters: 10797 + dm - The `DM` 10798 - dummy - unused argument 10799 10800 Options Database Key: 10801 . -dm_plex_monitor_throughput - Activate the monitor 10802 10803 Level: developer 10804 10805 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10806 @*/ 10807 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10808 { 10809 PetscLogHandler default_handler; 10810 10811 PetscFunctionBegin; 10812 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10813 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10814 if (default_handler) { 10815 PetscLogEvent event; 10816 PetscEventPerfInfo eventInfo; 10817 PetscLogDouble cellRate, flopRate; 10818 PetscInt cStart, cEnd, Nf, N; 10819 const char *name; 10820 10821 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10822 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10823 PetscCall(DMGetNumFields(dm, &Nf)); 10824 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10825 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10826 N = (cEnd - cStart) * Nf * eventInfo.count; 10827 flopRate = eventInfo.flops / eventInfo.time; 10828 cellRate = N / eventInfo.time; 10829 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)); 10830 } else { 10831 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."); 10832 } 10833 PetscFunctionReturn(PETSC_SUCCESS); 10834 } 10835