1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeMultistage, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_CreateBoxSFC, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 PetscLogEvent DMPLEX_DistributionView, DMPLEX_DistributionLoad; 17 18 PetscBool Plexcite = PETSC_FALSE; 19 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 20 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 21 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 22 "journal = {SIAM Journal on Scientific Computing},\n" 23 "volume = {38},\n" 24 "number = {5},\n" 25 "pages = {S143--S155},\n" 26 "eprint = {http://arxiv.org/abs/1506.07749},\n" 27 "doi = {10.1137/15M1026092},\n" 28 "year = {2016},\n" 29 "petsc_uses={DMPlex},\n}\n"; 30 31 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 32 33 /*@ 34 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 35 36 Input Parameter: 37 . dm - The `DMPLEX` object 38 39 Output Parameter: 40 . simplex - Flag checking for a simplex 41 42 Level: intermediate 43 44 Note: 45 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 46 If the mesh has no cells, this returns `PETSC_FALSE`. 47 48 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 49 @*/ 50 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 51 { 52 DMPolytopeType ct; 53 PetscInt cStart, cEnd; 54 55 PetscFunctionBegin; 56 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 57 if (cEnd <= cStart) { 58 *simplex = PETSC_FALSE; 59 PetscFunctionReturn(PETSC_SUCCESS); 60 } 61 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 62 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 63 PetscFunctionReturn(PETSC_SUCCESS); 64 } 65 66 /*@ 67 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 68 69 Input Parameters: 70 + dm - The `DMPLEX` object 71 - height - The cell height in the Plex, 0 is the default 72 73 Output Parameters: 74 + cStart - The first "normal" cell, pass `NULL` if not needed 75 - cEnd - The upper bound on "normal" cells, pass `NULL` if not needed 76 77 Level: developer 78 79 Note: 80 This function requires that tensor cells are ordered last. 81 82 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 83 @*/ 84 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PeOp PetscInt *cStart, PeOp PetscInt *cEnd) 85 { 86 DMLabel ctLabel; 87 IS valueIS; 88 const PetscInt *ctypes; 89 PetscBool found = PETSC_FALSE; 90 PetscInt Nct, cS = PETSC_INT_MAX, cE = 0; 91 92 PetscFunctionBegin; 93 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 94 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 95 PetscCall(ISGetLocalSize(valueIS, &Nct)); 96 PetscCall(ISGetIndices(valueIS, &ctypes)); 97 for (PetscInt t = 0; t < Nct; ++t) { 98 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 99 PetscInt ctS, ctE, ht; 100 101 if (ct == DM_POLYTOPE_UNKNOWN) { 102 // If any cells are not typed, just use all cells 103 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 104 break; 105 } 106 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 107 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 108 if (ctS >= ctE) continue; 109 // Check that a point has the right height 110 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 111 if (ht != height) continue; 112 cS = PetscMin(cS, ctS); 113 cE = PetscMax(cE, ctE); 114 found = PETSC_TRUE; 115 } 116 if (!Nct || !found) cS = cE = 0; 117 PetscCall(ISDestroy(&valueIS)); 118 // Reset label for fast lookup 119 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 120 if (cStart) *cStart = cS; 121 if (cEnd) *cEnd = cE; 122 PetscFunctionReturn(PETSC_SUCCESS); 123 } 124 125 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 126 { 127 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 128 PetscInt *sStart, *sEnd; 129 PetscViewerVTKFieldType *ft; 130 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 131 DMLabel depthLabel, ctLabel; 132 133 PetscFunctionBegin; 134 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 135 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 136 PetscCall(DMGetCoordinateDim(dm, &cdim)); 137 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 138 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 139 if (field >= 0) { 140 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 141 } else { 142 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 143 } 144 145 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 146 PetscCall(DMPlexGetDepth(dm, &depth)); 147 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 148 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 149 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 150 const DMPolytopeType ict = (DMPolytopeType)c; 151 PetscInt dep; 152 153 if (ict == DM_POLYTOPE_FV_GHOST) continue; 154 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 155 if (pStart >= 0) { 156 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 157 if (dep != depth - cellHeight) continue; 158 } 159 if (field >= 0) { 160 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 161 } else { 162 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 163 } 164 } 165 166 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 167 *types = 0; 168 169 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 170 if (globalvcdof[c]) ++(*types); 171 } 172 173 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 174 t = 0; 175 if (globalvcdof[DM_NUM_POLYTOPES]) { 176 sStart[t] = vStart; 177 sEnd[t] = vEnd; 178 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 179 ++t; 180 } 181 182 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 183 if (globalvcdof[c]) { 184 const DMPolytopeType ict = (DMPolytopeType)c; 185 186 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 187 sStart[t] = cStart; 188 sEnd[t] = cEnd; 189 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 190 ++t; 191 } 192 } 193 194 if (!*types) { 195 if (field >= 0) { 196 const char *fieldname; 197 198 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 199 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 200 } else { 201 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 202 } 203 } 204 205 *ssStart = sStart; 206 *ssEnd = sEnd; 207 *sft = ft; 208 PetscFunctionReturn(PETSC_SUCCESS); 209 } 210 211 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 212 { 213 PetscFunctionBegin; 214 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 215 PetscFunctionReturn(PETSC_SUCCESS); 216 } 217 218 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 219 { 220 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 221 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 222 223 PetscFunctionBegin; 224 *ft = PETSC_VTK_INVALID; 225 PetscCall(DMGetCoordinateDim(dm, &cdim)); 226 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 227 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 228 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 229 if (field >= 0) { 230 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 231 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 232 } else { 233 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 234 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 235 } 236 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 237 if (globalvcdof[0]) { 238 *sStart = vStart; 239 *sEnd = vEnd; 240 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 241 else *ft = PETSC_VTK_POINT_FIELD; 242 } else if (globalvcdof[1]) { 243 *sStart = cStart; 244 *sEnd = cEnd; 245 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 246 else *ft = PETSC_VTK_CELL_FIELD; 247 } else { 248 if (field >= 0) { 249 const char *fieldname; 250 251 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 252 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 253 } else { 254 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n")); 255 } 256 } 257 PetscFunctionReturn(PETSC_SUCCESS); 258 } 259 260 /*@ 261 DMPlexVecView1D - Plot many 1D solutions on the same line graph 262 263 Collective 264 265 Input Parameters: 266 + dm - The `DMPLEX` object 267 . n - The number of vectors 268 . u - The array of local vectors 269 - viewer - The `PetscViewer` 270 271 Level: advanced 272 273 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 274 @*/ 275 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 276 { 277 DM cdm; 278 PetscDS ds; 279 PetscDraw draw = NULL; 280 PetscDrawLG lg; 281 Vec coordinates; 282 const PetscScalar *coords, **sol; 283 PetscReal *vals; 284 PetscInt *Nc; 285 PetscInt Nf, Nl, vStart, vEnd, eStart, eEnd; 286 char **names; 287 288 PetscFunctionBegin; 289 PetscCall(DMGetCoordinateDM(dm, &cdm)); 290 PetscCall(DMGetDS(dm, &ds)); 291 PetscCall(PetscDSGetNumFields(ds, &Nf)); 292 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 293 PetscCall(PetscDSGetComponents(ds, &Nc)); 294 295 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 296 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 297 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 298 299 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 300 for (PetscInt i = 0, l = 0; i < n; ++i) { 301 const char *vname; 302 303 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 304 for (PetscInt f = 0; f < Nf; ++f) { 305 PetscObject disc; 306 const char *fname; 307 char tmpname[PETSC_MAX_PATH_LEN]; 308 309 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 310 /* TODO Create names for components */ 311 for (PetscInt c = 0; c < Nc[f]; ++c, ++l) { 312 PetscCall(PetscObjectGetName(disc, &fname)); 313 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 314 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 315 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 316 PetscCall(PetscStrallocpy(tmpname, &names[l])); 317 } 318 } 319 } 320 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 321 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 322 PetscCall(VecGetArrayRead(coordinates, &coords)); 323 for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 324 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 325 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 326 PetscSection s; 327 PetscInt cdof, vdof; 328 329 PetscCall(DMGetLocalSection(dm, &s)); 330 PetscCall(PetscSectionGetDof(s, eStart, &cdof)); 331 PetscCall(PetscSectionGetDof(s, vStart, &vdof)); 332 if (cdof) { 333 if (vdof) { 334 // P_2 335 PetscInt vFirst = -1; 336 337 for (PetscInt e = eStart; e < eEnd; ++e) { 338 PetscScalar *xa, *xb, *svals; 339 const PetscInt *cone; 340 341 PetscCall(DMPlexGetCone(dm, e, &cone)); 342 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 343 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 344 if (e == eStart) vFirst = cone[0]; 345 for (PetscInt i = 0; i < n; ++i) { 346 PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals)); 347 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 348 } 349 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals)); 350 if (e == eEnd - 1 && cone[1] != vFirst) { 351 for (PetscInt i = 0; i < n; ++i) { 352 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 353 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 354 } 355 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 356 for (PetscInt i = 0; i < n; ++i) { 357 PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals)); 358 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 359 } 360 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals)); 361 } 362 } 363 } else { 364 // P_0 365 for (PetscInt e = eStart; e < eEnd; ++e) { 366 PetscScalar *xa, *xb, *svals; 367 const PetscInt *cone; 368 369 PetscCall(DMPlexGetCone(dm, e, &cone)); 370 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 371 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 372 for (PetscInt i = 0; i < n; ++i) { 373 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 374 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 375 } 376 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 377 } 378 } 379 } else if (vdof) { 380 // P_1 381 for (PetscInt v = vStart; v < vEnd; ++v) { 382 PetscScalar *x, *svals; 383 384 PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x)); 385 for (PetscInt i = 0; i < n; ++i) { 386 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 387 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 388 } 389 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 390 } 391 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Discretization not supported"); 392 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 393 for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 394 for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 395 PetscCall(PetscFree3(sol, names, vals)); 396 397 PetscCall(PetscDrawLGDraw(lg)); 398 PetscCall(PetscDrawLGDestroy(&lg)); 399 PetscFunctionReturn(PETSC_SUCCESS); 400 } 401 402 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 403 { 404 DM dm; 405 406 PetscFunctionBegin; 407 PetscCall(VecGetDM(u, &dm)); 408 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 409 PetscFunctionReturn(PETSC_SUCCESS); 410 } 411 412 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 413 { 414 DM dm; 415 PetscSection s; 416 PetscDraw draw, popup; 417 DM cdm; 418 PetscSection coordSection; 419 Vec coordinates; 420 const PetscScalar *array; 421 PetscReal lbound[3], ubound[3]; 422 PetscReal vbound[2], time; 423 PetscBool flg; 424 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 425 const char *name; 426 char title[PETSC_MAX_PATH_LEN]; 427 428 PetscFunctionBegin; 429 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 430 PetscCall(VecGetDM(v, &dm)); 431 PetscCall(DMGetCoordinateDim(dm, &dim)); 432 PetscCall(DMGetLocalSection(dm, &s)); 433 PetscCall(PetscSectionGetNumFields(s, &Nf)); 434 PetscCall(DMGetCoarsenLevel(dm, &level)); 435 PetscCall(DMGetCoordinateDM(dm, &cdm)); 436 PetscCall(DMGetLocalSection(cdm, &coordSection)); 437 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 438 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 439 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 440 441 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 442 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 443 444 PetscCall(VecGetLocalSize(coordinates, &N)); 445 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 446 PetscCall(PetscDrawClear(draw)); 447 448 /* Could implement something like DMDASelectFields() */ 449 for (f = 0; f < Nf; ++f) { 450 DM fdm = dm; 451 Vec fv = v; 452 IS fis; 453 char prefix[PETSC_MAX_PATH_LEN]; 454 const char *fname; 455 456 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 457 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 458 459 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 460 else prefix[0] = '\0'; 461 if (Nf > 1) { 462 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 463 PetscCall(VecGetSubVector(v, fis, &fv)); 464 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 465 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 466 } 467 for (comp = 0; comp < Nc; ++comp, ++w) { 468 PetscInt nmax = 2; 469 470 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 471 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 472 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 473 PetscCall(PetscDrawSetTitle(draw, title)); 474 475 /* TODO Get max and min only for this component */ 476 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 477 if (!flg) { 478 PetscCall(VecMin(fv, NULL, &vbound[0])); 479 PetscCall(VecMax(fv, NULL, &vbound[1])); 480 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 481 } 482 483 PetscCall(PetscDrawGetPopup(draw, &popup)); 484 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 485 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 486 PetscCall(VecGetArrayRead(fv, &array)); 487 for (c = cStart; c < cEnd; ++c) { 488 DMPolytopeType ct; 489 PetscScalar *coords = NULL, *a = NULL; 490 const PetscScalar *coords_arr; 491 PetscBool isDG; 492 PetscInt numCoords; 493 int color[4] = {-1, -1, -1, -1}; 494 495 PetscCall(DMPlexGetCellType(dm, c, &ct)); 496 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 497 if (a) { 498 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 499 color[1] = color[2] = color[3] = color[0]; 500 } else { 501 PetscScalar *vals = NULL; 502 PetscInt numVals, va; 503 504 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 505 if (!numVals) { 506 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 507 continue; 508 } 509 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 510 switch (numVals / Nc) { 511 case 1: /* P1 Clamped Segment Prism */ 512 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 513 PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]); 514 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 515 break; 516 case 3: /* P1 Triangle */ 517 case 4: /* P1 Quadrangle */ 518 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 519 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 520 break; 521 case 6: /* P2 Triangle */ 522 case 8: /* P2 Quadrangle */ 523 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 524 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 525 break; 526 default: 527 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 528 } 529 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 530 } 531 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 532 switch (numCoords) { 533 case 6: 534 case 12: /* Localized triangle */ 535 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 536 break; 537 case 8: 538 case 16: /* Localized quadrilateral */ 539 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 540 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 541 } else { 542 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 543 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 544 } 545 break; 546 default: 547 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 548 } 549 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 550 } 551 PetscCall(VecRestoreArrayRead(fv, &array)); 552 PetscCall(PetscDrawFlush(draw)); 553 PetscCall(PetscDrawPause(draw)); 554 PetscCall(PetscDrawSave(draw)); 555 } 556 if (Nf > 1) { 557 PetscCall(VecRestoreSubVector(v, fis, &fv)); 558 PetscCall(ISDestroy(&fis)); 559 PetscCall(DMDestroy(&fdm)); 560 } 561 } 562 PetscFunctionReturn(PETSC_SUCCESS); 563 } 564 565 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 566 { 567 DM dm; 568 PetscDraw draw; 569 PetscInt dim; 570 PetscBool isnull; 571 572 PetscFunctionBegin; 573 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 574 PetscCall(PetscDrawIsNull(draw, &isnull)); 575 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 576 577 PetscCall(VecGetDM(v, &dm)); 578 PetscCall(DMGetCoordinateDim(dm, &dim)); 579 switch (dim) { 580 case 1: 581 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 582 break; 583 case 2: 584 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 585 break; 586 default: 587 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 588 } 589 PetscFunctionReturn(PETSC_SUCCESS); 590 } 591 592 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 593 { 594 DM dm; 595 Vec locv; 596 const char *name; 597 PetscSection section; 598 PetscInt pStart, pEnd; 599 PetscInt numFields; 600 PetscViewerVTKFieldType ft; 601 602 PetscFunctionBegin; 603 PetscCall(VecGetDM(v, &dm)); 604 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 605 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 606 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 607 PetscCall(VecCopy(v, locv)); 608 PetscCall(DMGetLocalSection(dm, §ion)); 609 PetscCall(PetscSectionGetNumFields(section, &numFields)); 610 if (!numFields) { 611 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 612 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 613 } else { 614 PetscInt f; 615 616 for (f = 0; f < numFields; f++) { 617 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 618 if (ft == PETSC_VTK_INVALID) continue; 619 PetscCall(PetscObjectReference((PetscObject)locv)); 620 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 621 } 622 PetscCall(VecDestroy(&locv)); 623 } 624 PetscFunctionReturn(PETSC_SUCCESS); 625 } 626 627 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 640 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 641 if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) { 642 PetscInt i, numFields; 643 PetscObject fe; 644 PetscBool fem = PETSC_FALSE; 645 Vec locv = v; 646 const char *name; 647 PetscInt step; 648 PetscReal time; 649 650 PetscCall(DMGetNumFields(dm, &numFields)); 651 for (i = 0; i < numFields; i++) { 652 PetscCall(DMGetField(dm, i, NULL, &fe)); 653 if (fe->classid == PETSCFE_CLASSID) { 654 fem = PETSC_TRUE; 655 break; 656 } 657 } 658 if (fem) { 659 PetscObject isZero; 660 661 PetscCall(DMGetLocalVector(dm, &locv)); 662 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 663 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 664 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 665 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 666 PetscCall(VecCopy(v, locv)); 667 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 668 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 669 } 670 if (isvtk) { 671 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 672 } else if (ishdf5) { 673 #if defined(PETSC_HAVE_HDF5) 674 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 675 #else 676 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 677 #endif 678 } else if (isdraw) { 679 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 680 } else if (ispython) { 681 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv)); 682 } else if (isglvis) { 683 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 684 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 685 PetscCall(VecView_GLVis(locv, viewer)); 686 } else if (iscgns) { 687 #if defined(PETSC_HAVE_CGNS) 688 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 689 #else 690 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 691 #endif 692 } 693 if (fem) { 694 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 695 PetscCall(DMRestoreLocalVector(dm, &locv)); 696 } 697 } else { 698 PetscBool isseq; 699 700 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 701 if (isseq) PetscCall(VecView_Seq(v, viewer)); 702 else PetscCall(VecView_MPI(v, viewer)); 703 } 704 PetscFunctionReturn(PETSC_SUCCESS); 705 } 706 707 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 708 { 709 DM dm; 710 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython; 711 712 PetscFunctionBegin; 713 PetscCall(VecGetDM(v, &dm)); 714 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 715 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 716 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 721 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 722 if (isvtk || isdraw || isglvis || iscgns || ispython) { 723 Vec locv; 724 PetscObject isZero; 725 const char *name; 726 727 PetscCall(DMGetLocalVector(dm, &locv)); 728 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 729 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 730 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 731 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 732 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 733 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 734 PetscCall(VecView_Plex_Local(locv, viewer)); 735 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 736 PetscCall(DMRestoreLocalVector(dm, &locv)); 737 } else if (ishdf5) { 738 #if defined(PETSC_HAVE_HDF5) 739 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 740 #else 741 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 742 #endif 743 } else if (isexodusii) { 744 #if defined(PETSC_HAVE_EXODUSII) 745 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 746 #else 747 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 748 #endif 749 } else { 750 PetscBool isseq; 751 752 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 753 if (isseq) PetscCall(VecView_Seq(v, viewer)); 754 else PetscCall(VecView_MPI(v, viewer)); 755 } 756 PetscFunctionReturn(PETSC_SUCCESS); 757 } 758 759 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 760 { 761 DM dm; 762 MPI_Comm comm; 763 PetscViewerFormat format; 764 Vec v; 765 PetscBool isvtk, ishdf5; 766 767 PetscFunctionBegin; 768 PetscCall(VecGetDM(originalv, &dm)); 769 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 770 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 771 PetscCall(PetscViewerGetFormat(viewer, &format)); 772 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 773 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 774 if (format == PETSC_VIEWER_NATIVE) { 775 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 776 /* this need a better fix */ 777 if (dm->useNatural) { 778 const char *vecname; 779 PetscInt n, nroots; 780 781 PetscCheck(dm->sfNatural, comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 782 PetscCall(VecGetLocalSize(originalv, &n)); 783 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 784 PetscCheck(n == nroots, comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 785 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 786 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 787 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 788 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 789 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 790 } else v = originalv; 791 } else v = originalv; 792 793 if (ishdf5) { 794 #if defined(PETSC_HAVE_HDF5) 795 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 796 #else 797 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 798 #endif 799 } else if (isvtk) { 800 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 801 } else { 802 PetscBool isseq; 803 804 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 805 if (isseq) PetscCall(VecView_Seq(v, viewer)); 806 else PetscCall(VecView_MPI(v, viewer)); 807 } 808 if (v != originalv) PetscCall(VecDestroy(&v)); 809 PetscFunctionReturn(PETSC_SUCCESS); 810 } 811 812 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 813 { 814 DM dm; 815 PetscBool ishdf5; 816 817 PetscFunctionBegin; 818 PetscCall(VecGetDM(v, &dm)); 819 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 820 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 821 if (ishdf5) { 822 DM dmBC; 823 Vec gv; 824 const char *name; 825 826 PetscCall(DMGetOutputDM(dm, &dmBC)); 827 PetscCall(DMGetGlobalVector(dmBC, &gv)); 828 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 829 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 830 PetscCall(VecLoad_Default(gv, viewer)); 831 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 832 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 833 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 834 } else PetscCall(VecLoad_Default(v, viewer)); 835 PetscFunctionReturn(PETSC_SUCCESS); 836 } 837 838 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 839 { 840 DM dm; 841 PetscBool ishdf5, isexodusii, iscgns; 842 843 PetscFunctionBegin; 844 PetscCall(VecGetDM(v, &dm)); 845 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 846 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 847 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 848 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 849 if (ishdf5) { 850 #if defined(PETSC_HAVE_HDF5) 851 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 852 #else 853 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 854 #endif 855 } else if (isexodusii) { 856 #if defined(PETSC_HAVE_EXODUSII) 857 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 858 #else 859 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 860 #endif 861 } else if (iscgns) { 862 #if defined(PETSC_HAVE_CGNS) 863 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 864 #else 865 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 866 #endif 867 } else PetscCall(VecLoad_Default(v, viewer)); 868 PetscFunctionReturn(PETSC_SUCCESS); 869 } 870 871 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 872 { 873 DM dm; 874 PetscViewerFormat format; 875 PetscBool ishdf5; 876 877 PetscFunctionBegin; 878 PetscCall(VecGetDM(originalv, &dm)); 879 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 880 PetscCall(PetscViewerGetFormat(viewer, &format)); 881 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 882 if (format == PETSC_VIEWER_NATIVE) { 883 if (dm->useNatural) { 884 if (dm->sfNatural) { 885 if (ishdf5) { 886 #if defined(PETSC_HAVE_HDF5) 887 Vec v; 888 const char *vecname; 889 890 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 891 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 892 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 893 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 894 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 895 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 896 PetscCall(VecDestroy(&v)); 897 #else 898 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 899 #endif 900 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 901 } 902 } else PetscCall(VecLoad_Default(originalv, viewer)); 903 } 904 PetscFunctionReturn(PETSC_SUCCESS); 905 } 906 907 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 908 { 909 PetscSection coordSection; 910 Vec coordinates; 911 DMLabel depthLabel, celltypeLabel; 912 const char *name[4]; 913 const PetscScalar *a; 914 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 915 916 PetscFunctionBegin; 917 PetscCall(DMGetDimension(dm, &dim)); 918 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 919 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 920 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 921 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 922 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 923 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 924 PetscCall(VecGetArrayRead(coordinates, &a)); 925 name[0] = "vertex"; 926 name[1] = "edge"; 927 name[dim - 1] = "face"; 928 name[dim] = "cell"; 929 for (c = cStart; c < cEnd; ++c) { 930 PetscInt *closure = NULL; 931 PetscInt closureSize, cl, ct; 932 933 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 934 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 935 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 936 PetscCall(PetscViewerASCIIPushTab(viewer)); 937 for (cl = 0; cl < closureSize * 2; cl += 2) { 938 PetscInt point = closure[cl], depth, dof, off, d, p; 939 940 if ((point < pStart) || (point >= pEnd)) continue; 941 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 942 if (!dof) continue; 943 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 944 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 945 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 946 for (p = 0; p < dof / dim; ++p) { 947 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 948 for (d = 0; d < dim; ++d) { 949 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 950 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 951 } 952 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 953 } 954 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 955 } 956 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 957 PetscCall(PetscViewerASCIIPopTab(viewer)); 958 } 959 PetscCall(VecRestoreArrayRead(coordinates, &a)); 960 PetscFunctionReturn(PETSC_SUCCESS); 961 } 962 963 typedef enum { 964 CS_CARTESIAN, 965 CS_POLAR, 966 CS_CYLINDRICAL, 967 CS_SPHERICAL 968 } CoordSystem; 969 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 970 971 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 972 { 973 PetscInt i; 974 975 PetscFunctionBegin; 976 if (dim > 3) { 977 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 978 } else { 979 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 980 981 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 982 switch (cs) { 983 case CS_CARTESIAN: 984 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 985 break; 986 case CS_POLAR: 987 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 988 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 989 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 990 break; 991 case CS_CYLINDRICAL: 992 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 993 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 994 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 995 trcoords[2] = coords[2]; 996 break; 997 case CS_SPHERICAL: 998 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 999 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 1000 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 1001 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 1002 break; 1003 } 1004 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 1005 } 1006 PetscFunctionReturn(PETSC_SUCCESS); 1007 } 1008 1009 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 1010 { 1011 DM_Plex *mesh = (DM_Plex *)dm->data; 1012 DM cdm, cdmCell; 1013 PetscSection coordSection, coordSectionCell; 1014 Vec coordinates, coordinatesCell; 1015 PetscViewerFormat format; 1016 1017 PetscFunctionBegin; 1018 PetscCall(PetscViewerGetFormat(viewer, &format)); 1019 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1020 const char *name; 1021 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1022 PetscInt pStart, pEnd, p, numLabels, l; 1023 PetscMPIInt rank, size; 1024 1025 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1026 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1027 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1028 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1029 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1030 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1031 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1032 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1033 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1034 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1035 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1036 PetscCall(DMGetDimension(dm, &dim)); 1037 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1038 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1039 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1040 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1041 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1042 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1043 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1044 for (p = pStart; p < pEnd; ++p) { 1045 PetscInt dof, off, s; 1046 1047 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1048 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1049 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1050 } 1051 PetscCall(PetscViewerFlush(viewer)); 1052 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1053 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1054 for (p = pStart; p < pEnd; ++p) { 1055 PetscInt dof, off, c; 1056 1057 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1058 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1059 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 1060 } 1061 PetscCall(PetscViewerFlush(viewer)); 1062 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1063 if (coordSection && coordinates) { 1064 CoordSystem cs = CS_CARTESIAN; 1065 const PetscScalar *array, *arrayCell = NULL; 1066 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1067 PetscMPIInt rank; 1068 const char *name; 1069 1070 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1071 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1072 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1073 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1074 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1075 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1076 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1077 pStart = PetscMin(pvStart, pcStart); 1078 pEnd = PetscMax(pvEnd, pcEnd); 1079 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1080 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1081 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1082 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1083 1084 PetscCall(VecGetArrayRead(coordinates, &array)); 1085 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1086 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1087 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1088 for (p = pStart; p < pEnd; ++p) { 1089 PetscInt dof, off; 1090 1091 if (p >= pvStart && p < pvEnd) { 1092 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1093 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1094 if (dof) { 1095 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1096 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1097 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1098 } 1099 } 1100 if (cdmCell && p >= pcStart && p < pcEnd) { 1101 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1102 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1103 if (dof) { 1104 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1105 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1106 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1107 } 1108 } 1109 } 1110 PetscCall(PetscViewerFlush(viewer)); 1111 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1112 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1113 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1114 } 1115 PetscCall(DMGetNumLabels(dm, &numLabels)); 1116 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1117 for (l = 0; l < numLabels; ++l) { 1118 DMLabel label; 1119 PetscBool isdepth; 1120 const char *name; 1121 1122 PetscCall(DMGetLabelName(dm, l, &name)); 1123 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1124 if (isdepth) continue; 1125 PetscCall(DMGetLabel(dm, name, &label)); 1126 PetscCall(DMLabelView(label, viewer)); 1127 } 1128 if (size > 1) { 1129 PetscSF sf; 1130 1131 PetscCall(DMGetPointSF(dm, &sf)); 1132 PetscCall(PetscSFView(sf, viewer)); 1133 } 1134 if (mesh->periodic.face_sfs) 1135 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1136 PetscCall(PetscViewerFlush(viewer)); 1137 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1138 const char *name, *color; 1139 const char *defcolors[3] = {"gray", "orange", "green"}; 1140 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1141 char lname[PETSC_MAX_PATH_LEN]; 1142 PetscReal scale = 2.0; 1143 PetscReal tikzscale = 1.0; 1144 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1145 double tcoords[3]; 1146 PetscScalar *coords; 1147 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 1148 PetscMPIInt rank, size; 1149 char **names, **colors, **lcolors; 1150 PetscBool flg, lflg; 1151 PetscBT wp = NULL; 1152 PetscInt pEnd, pStart; 1153 1154 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1155 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1156 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1157 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1158 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1159 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1160 PetscCall(DMGetDimension(dm, &dim)); 1161 PetscCall(DMPlexGetDepth(dm, &depth)); 1162 PetscCall(DMGetNumLabels(dm, &numLabels)); 1163 numLabels = PetscMax(numLabels, 10); 1164 numColors = 10; 1165 numLColors = 10; 1166 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1167 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1168 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1169 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1170 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1171 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1172 n = 4; 1173 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1174 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1175 n = 4; 1176 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1177 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1178 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1179 if (!useLabels) numLabels = 0; 1180 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1181 if (!useColors) { 1182 numColors = 3; 1183 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1184 } 1185 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1186 if (!useColors) { 1187 numLColors = 4; 1188 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1189 } 1190 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1191 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1192 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1193 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1194 if (depth < dim) plotEdges = PETSC_FALSE; 1195 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1196 1197 /* filter points with labelvalue != labeldefaultvalue */ 1198 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1199 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1200 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1201 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1202 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1203 if (lflg) { 1204 DMLabel lbl; 1205 1206 PetscCall(DMGetLabel(dm, lname, &lbl)); 1207 if (lbl) { 1208 PetscInt val, defval; 1209 1210 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1211 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1212 for (c = pStart; c < pEnd; c++) { 1213 PetscInt *closure = NULL; 1214 PetscInt closureSize; 1215 1216 PetscCall(DMLabelGetValue(lbl, c, &val)); 1217 if (val == defval) continue; 1218 1219 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1220 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1221 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1222 } 1223 } 1224 } 1225 1226 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1227 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1228 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1229 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1230 \\documentclass[tikz]{standalone}\n\n\ 1231 \\usepackage{pgflibraryshapes}\n\ 1232 \\usetikzlibrary{backgrounds}\n\ 1233 \\usetikzlibrary{arrows}\n\ 1234 \\begin{document}\n")); 1235 if (size > 1) { 1236 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1237 for (p = 0; p < size; ++p) { 1238 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1239 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1240 } 1241 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1242 } 1243 if (drawHasse) { 1244 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1245 1246 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1249 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1258 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1262 } 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1264 1265 /* Plot vertices */ 1266 PetscCall(VecGetArray(coordinates, &coords)); 1267 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1268 for (v = vStart; v < vEnd; ++v) { 1269 PetscInt off, dof, d; 1270 PetscBool isLabeled = PETSC_FALSE; 1271 1272 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1273 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1274 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1275 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1276 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1277 for (d = 0; d < dof; ++d) { 1278 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1279 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1280 } 1281 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1282 if (dim == 3) { 1283 PetscReal tmp = tcoords[1]; 1284 tcoords[1] = tcoords[2]; 1285 tcoords[2] = -tmp; 1286 } 1287 for (d = 0; d < dof; ++d) { 1288 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1289 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1290 } 1291 if (drawHasse) color = colors[0 % numColors]; 1292 else color = colors[rank % numColors]; 1293 for (l = 0; l < numLabels; ++l) { 1294 PetscInt val; 1295 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1296 if (val >= 0) { 1297 color = lcolors[l % numLColors]; 1298 isLabeled = PETSC_TRUE; 1299 break; 1300 } 1301 } 1302 if (drawNumbers[0]) { 1303 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1304 } else if (drawColors[0]) { 1305 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1306 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1307 } 1308 PetscCall(VecRestoreArray(coordinates, &coords)); 1309 PetscCall(PetscViewerFlush(viewer)); 1310 /* Plot edges */ 1311 if (plotEdges) { 1312 PetscCall(VecGetArray(coordinates, &coords)); 1313 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1314 for (e = eStart; e < eEnd; ++e) { 1315 const PetscInt *cone; 1316 PetscInt coneSize, offA, offB, dof, d; 1317 1318 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1319 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1320 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1321 PetscCall(DMPlexGetCone(dm, e, &cone)); 1322 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1323 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1324 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1325 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1326 for (d = 0; d < dof; ++d) { 1327 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1328 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1329 } 1330 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1331 if (dim == 3) { 1332 PetscReal tmp = tcoords[1]; 1333 tcoords[1] = tcoords[2]; 1334 tcoords[2] = -tmp; 1335 } 1336 for (d = 0; d < dof; ++d) { 1337 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1338 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1339 } 1340 if (drawHasse) color = colors[1 % numColors]; 1341 else color = colors[rank % numColors]; 1342 for (l = 0; l < numLabels; ++l) { 1343 PetscInt val; 1344 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1345 if (val >= 0) { 1346 color = lcolors[l % numLColors]; 1347 break; 1348 } 1349 } 1350 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1351 } 1352 PetscCall(VecRestoreArray(coordinates, &coords)); 1353 PetscCall(PetscViewerFlush(viewer)); 1354 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1355 } 1356 /* Plot cells */ 1357 if (dim == 3 || !drawNumbers[1]) { 1358 for (e = eStart; e < eEnd; ++e) { 1359 const PetscInt *cone; 1360 1361 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1362 color = colors[rank % numColors]; 1363 for (l = 0; l < numLabels; ++l) { 1364 PetscInt val; 1365 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1366 if (val >= 0) { 1367 color = lcolors[l % numLColors]; 1368 break; 1369 } 1370 } 1371 PetscCall(DMPlexGetCone(dm, e, &cone)); 1372 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1373 } 1374 } else { 1375 DMPolytopeType ct; 1376 1377 /* Drawing a 2D polygon */ 1378 for (c = cStart; c < cEnd; ++c) { 1379 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1380 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1381 if (DMPolytopeTypeIsHybrid(ct)) { 1382 const PetscInt *cone; 1383 PetscInt coneSize, e; 1384 1385 PetscCall(DMPlexGetCone(dm, c, &cone)); 1386 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1387 for (e = 0; e < coneSize; ++e) { 1388 const PetscInt *econe; 1389 1390 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1391 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1392 } 1393 } else { 1394 PetscInt *closure = NULL; 1395 PetscInt closureSize, Nv = 0, v; 1396 1397 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1398 for (p = 0; p < closureSize * 2; p += 2) { 1399 const PetscInt point = closure[p]; 1400 1401 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1402 } 1403 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1404 for (v = 0; v <= Nv; ++v) { 1405 const PetscInt vertex = closure[v % Nv]; 1406 1407 if (v > 0) { 1408 if (plotEdges) { 1409 const PetscInt *edge; 1410 PetscInt endpoints[2], ne; 1411 1412 endpoints[0] = closure[v - 1]; 1413 endpoints[1] = vertex; 1414 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1415 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1416 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1417 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1418 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1419 } 1420 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1421 } 1422 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1423 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1424 } 1425 } 1426 } 1427 for (c = cStart; c < cEnd; ++c) { 1428 double ccoords[3] = {0.0, 0.0, 0.0}; 1429 PetscBool isLabeled = PETSC_FALSE; 1430 PetscScalar *cellCoords = NULL; 1431 const PetscScalar *array; 1432 PetscInt numCoords, cdim, d; 1433 PetscBool isDG; 1434 1435 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1436 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1437 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1438 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1439 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1440 for (p = 0; p < numCoords / cdim; ++p) { 1441 for (d = 0; d < cdim; ++d) { 1442 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1443 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1444 } 1445 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1446 if (cdim == 3) { 1447 PetscReal tmp = tcoords[1]; 1448 tcoords[1] = tcoords[2]; 1449 tcoords[2] = -tmp; 1450 } 1451 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1452 } 1453 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1454 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1455 for (d = 0; d < cdim; ++d) { 1456 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1457 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1458 } 1459 if (drawHasse) color = colors[depth % numColors]; 1460 else color = colors[rank % numColors]; 1461 for (l = 0; l < numLabels; ++l) { 1462 PetscInt val; 1463 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1464 if (val >= 0) { 1465 color = lcolors[l % numLColors]; 1466 isLabeled = PETSC_TRUE; 1467 break; 1468 } 1469 } 1470 if (drawNumbers[dim]) { 1471 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1472 } else if (drawColors[dim]) { 1473 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1474 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1475 } 1476 if (drawHasse) { 1477 int height = 0; 1478 1479 color = colors[depth % numColors]; 1480 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1481 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1482 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1483 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1484 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1485 1486 if (depth > 2) { 1487 color = colors[1 % numColors]; 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1489 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1490 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1491 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1492 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1493 } 1494 1495 color = colors[1 % numColors]; 1496 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1497 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1498 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1499 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1500 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1501 1502 color = colors[0 % numColors]; 1503 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1504 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1505 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1506 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1507 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1508 1509 for (p = pStart; p < pEnd; ++p) { 1510 const PetscInt *cone; 1511 PetscInt coneSize, cp; 1512 1513 PetscCall(DMPlexGetCone(dm, p, &cone)); 1514 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1515 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1516 } 1517 } 1518 PetscCall(PetscViewerFlush(viewer)); 1519 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1520 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1521 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1522 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1523 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1524 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1525 PetscCall(PetscFree3(names, colors, lcolors)); 1526 PetscCall(PetscBTDestroy(&wp)); 1527 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1528 Vec cown, acown; 1529 VecScatter sct; 1530 ISLocalToGlobalMapping g2l; 1531 IS gid, acis; 1532 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1533 MPI_Group ggroup, ngroup; 1534 PetscScalar *array, nid; 1535 const PetscInt *idxs; 1536 PetscInt *idxs2, *start, *adjacency, *work; 1537 PetscInt64 lm[3], gm[3]; 1538 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1539 PetscMPIInt d1, d2, rank; 1540 1541 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1542 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1543 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1544 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1545 #endif 1546 if (ncomm != MPI_COMM_NULL) { 1547 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1548 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1549 d1 = 0; 1550 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1551 nid = d2; 1552 PetscCallMPI(MPI_Group_free(&ggroup)); 1553 PetscCallMPI(MPI_Group_free(&ngroup)); 1554 PetscCallMPI(MPI_Comm_free(&ncomm)); 1555 } else nid = 0.0; 1556 1557 /* Get connectivity */ 1558 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1559 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1560 1561 /* filter overlapped local cells */ 1562 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1563 PetscCall(ISGetIndices(gid, &idxs)); 1564 PetscCall(ISGetLocalSize(gid, &cum)); 1565 PetscCall(PetscMalloc1(cum, &idxs2)); 1566 for (c = cStart, cum = 0; c < cEnd; c++) { 1567 if (idxs[c - cStart] < 0) continue; 1568 idxs2[cum++] = idxs[c - cStart]; 1569 } 1570 PetscCall(ISRestoreIndices(gid, &idxs)); 1571 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1572 PetscCall(ISDestroy(&gid)); 1573 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1574 1575 /* support for node-aware cell locality */ 1576 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1577 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1578 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1579 PetscCall(VecGetArray(cown, &array)); 1580 for (c = 0; c < numVertices; c++) array[c] = nid; 1581 PetscCall(VecRestoreArray(cown, &array)); 1582 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1583 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1584 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1585 PetscCall(ISDestroy(&acis)); 1586 PetscCall(VecScatterDestroy(&sct)); 1587 PetscCall(VecDestroy(&cown)); 1588 1589 /* compute edgeCut */ 1590 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1591 PetscCall(PetscMalloc1(cum, &work)); 1592 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1593 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1594 PetscCall(ISDestroy(&gid)); 1595 PetscCall(VecGetArray(acown, &array)); 1596 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1597 PetscInt totl; 1598 1599 totl = start[c + 1] - start[c]; 1600 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1601 for (i = 0; i < totl; i++) { 1602 if (work[i] < 0) { 1603 ect += 1; 1604 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1605 } 1606 } 1607 } 1608 PetscCall(PetscFree(work)); 1609 PetscCall(VecRestoreArray(acown, &array)); 1610 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1611 lm[1] = -numVertices; 1612 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1613 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1614 lm[0] = ect; /* edgeCut */ 1615 lm[1] = ectn; /* node-aware edgeCut */ 1616 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1617 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1618 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1619 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1620 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1621 #else 1622 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1623 #endif 1624 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1625 PetscCall(PetscFree(start)); 1626 PetscCall(PetscFree(adjacency)); 1627 PetscCall(VecDestroy(&acown)); 1628 } else { 1629 const char *name; 1630 PetscInt *sizes, *hybsizes, *ghostsizes; 1631 PetscInt locDepth, depth, cellHeight, dim, d; 1632 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1633 PetscInt numLabels, l, maxSize = 17; 1634 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1635 MPI_Comm comm; 1636 PetscMPIInt size, rank; 1637 1638 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1639 PetscCallMPI(MPI_Comm_size(comm, &size)); 1640 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1641 PetscCall(DMGetDimension(dm, &dim)); 1642 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1643 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1644 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1645 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1646 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1647 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1648 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1649 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1650 gcNum = gcEnd - gcStart; 1651 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1652 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1653 for (d = 0; d <= depth; d++) { 1654 PetscInt Nc[2] = {0, 0}, ict; 1655 1656 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1657 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1658 ict = ct0; 1659 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1660 ct0 = (DMPolytopeType)ict; 1661 for (p = pStart; p < pEnd; ++p) { 1662 DMPolytopeType ct; 1663 1664 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1665 if (ct == ct0) ++Nc[0]; 1666 else ++Nc[1]; 1667 } 1668 if (size < maxSize) { 1669 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1670 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1671 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1672 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1673 for (p = 0; p < size; ++p) { 1674 if (rank == 0) { 1675 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1676 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1677 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1678 } 1679 } 1680 } else { 1681 PetscInt locMinMax[2]; 1682 1683 locMinMax[0] = Nc[0] + Nc[1]; 1684 locMinMax[1] = Nc[0] + Nc[1]; 1685 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1686 locMinMax[0] = Nc[1]; 1687 locMinMax[1] = Nc[1]; 1688 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1689 if (d == depth) { 1690 locMinMax[0] = gcNum; 1691 locMinMax[1] = gcNum; 1692 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1693 } 1694 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1695 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1696 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1697 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1698 } 1699 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1700 } 1701 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1702 { 1703 const PetscReal *maxCell; 1704 const PetscReal *L; 1705 PetscBool localized; 1706 1707 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1708 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1709 if (L || localized) { 1710 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1711 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1712 if (L) { 1713 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1714 for (d = 0; d < dim; ++d) { 1715 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1716 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1717 } 1718 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1719 } 1720 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1721 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1722 } 1723 } 1724 PetscCall(DMGetNumLabels(dm, &numLabels)); 1725 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1726 for (l = 0; l < numLabels; ++l) { 1727 DMLabel label; 1728 const char *name; 1729 PetscInt *values; 1730 PetscInt numValues, v; 1731 1732 PetscCall(DMGetLabelName(dm, l, &name)); 1733 PetscCall(DMGetLabel(dm, name, &label)); 1734 PetscCall(DMLabelGetNumValues(label, &numValues)); 1735 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1736 1737 { // Extract array of DMLabel values so it can be sorted 1738 IS is_values; 1739 const PetscInt *is_values_local = NULL; 1740 1741 PetscCall(DMLabelGetValueIS(label, &is_values)); 1742 PetscCall(ISGetIndices(is_values, &is_values_local)); 1743 PetscCall(PetscMalloc1(numValues, &values)); 1744 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1745 PetscCall(PetscSortInt(numValues, values)); 1746 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1747 PetscCall(ISDestroy(&is_values)); 1748 } 1749 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1750 for (v = 0; v < numValues; ++v) { 1751 PetscInt size; 1752 1753 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1754 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1755 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1756 } 1757 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1758 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1759 PetscCall(PetscFree(values)); 1760 } 1761 { 1762 char **labelNames; 1763 PetscInt Nl = numLabels; 1764 PetscBool flg; 1765 1766 PetscCall(PetscMalloc1(Nl, &labelNames)); 1767 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1768 for (l = 0; l < Nl; ++l) { 1769 DMLabel label; 1770 1771 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1772 if (flg) { 1773 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1774 PetscCall(DMLabelView(label, viewer)); 1775 } 1776 PetscCall(PetscFree(labelNames[l])); 1777 } 1778 PetscCall(PetscFree(labelNames)); 1779 } 1780 /* If no fields are specified, people do not want to see adjacency */ 1781 if (dm->Nf) { 1782 PetscInt f; 1783 1784 for (f = 0; f < dm->Nf; ++f) { 1785 const char *name; 1786 1787 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1788 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1789 PetscCall(PetscViewerASCIIPushTab(viewer)); 1790 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1791 if (dm->fields[f].adjacency[0]) { 1792 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1793 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1794 } else { 1795 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1796 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1797 } 1798 PetscCall(PetscViewerASCIIPopTab(viewer)); 1799 } 1800 } 1801 DMPlexTransform tr; 1802 1803 PetscCall(DMPlexGetTransform(dm, &tr)); 1804 if (tr) { 1805 PetscCall(PetscViewerASCIIPushTab(viewer)); 1806 PetscCall(PetscViewerASCIIPrintf(viewer, "Created using transform:\n")); 1807 PetscCall(DMPlexTransformView(tr, viewer)); 1808 PetscCall(PetscViewerASCIIPopTab(viewer)); 1809 } 1810 PetscCall(DMGetCoarseDM(dm, &cdm)); 1811 if (cdm) { 1812 PetscCall(PetscViewerASCIIPushTab(viewer)); 1813 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1814 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1815 PetscCall(PetscViewerASCIIPopTab(viewer)); 1816 } 1817 } 1818 PetscFunctionReturn(PETSC_SUCCESS); 1819 } 1820 1821 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt lC, PetscInt cC, PetscInt cell, const PetscScalar coords[]) 1822 { 1823 DMPolytopeType ct; 1824 PetscMPIInt rank; 1825 PetscInt cdim; 1826 int lineColor, cellColor; 1827 1828 PetscFunctionBegin; 1829 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1830 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1831 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1832 lineColor = (int)(lC < 0 ? PETSC_DRAW_BLACK : lC); 1833 cellColor = (int)(cC < 0 ? PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2 : cC); 1834 switch (ct) { 1835 case DM_POLYTOPE_SEGMENT: 1836 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1837 switch (cdim) { 1838 case 1: { 1839 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1840 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1841 1842 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, lineColor)); 1843 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, lineColor)); 1844 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, lineColor)); 1845 } break; 1846 case 2: { 1847 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1848 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1849 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1850 1851 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1852 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, lineColor)); 1853 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, lineColor)); 1854 } break; 1855 default: 1856 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1857 } 1858 break; 1859 case DM_POLYTOPE_TRIANGLE: 1860 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1861 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1862 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1863 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1864 break; 1865 case DM_POLYTOPE_QUADRILATERAL: 1866 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1867 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), cellColor, cellColor, cellColor)); 1868 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1869 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1870 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor)); 1871 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1872 break; 1873 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1874 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1875 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1876 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1877 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor)); 1878 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1879 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1880 break; 1881 case DM_POLYTOPE_FV_GHOST: 1882 break; 1883 default: 1884 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1885 } 1886 PetscFunctionReturn(PETSC_SUCCESS); 1887 } 1888 1889 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1890 { 1891 PetscReal centroid[2] = {0., 0.}; 1892 PetscMPIInt rank; 1893 PetscMPIInt fillColor; 1894 1895 PetscFunctionBegin; 1896 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1897 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1898 for (PetscInt v = 0; v < Nv; ++v) { 1899 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1900 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1901 } 1902 for (PetscInt e = 0; e < Nv; ++e) { 1903 refCoords[0] = refVertices[e * 2 + 0]; 1904 refCoords[1] = refVertices[e * 2 + 1]; 1905 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1906 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1907 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1908 } 1909 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1910 for (PetscInt d = 0; d < edgeDiv; ++d) { 1911 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1912 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1913 } 1914 } 1915 PetscFunctionReturn(PETSC_SUCCESS); 1916 } 1917 1918 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1919 { 1920 DMPolytopeType ct; 1921 1922 PetscFunctionBegin; 1923 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1924 switch (ct) { 1925 case DM_POLYTOPE_TRIANGLE: { 1926 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1927 1928 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1929 } break; 1930 case DM_POLYTOPE_QUADRILATERAL: { 1931 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1932 1933 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1934 } break; 1935 default: 1936 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1937 } 1938 PetscFunctionReturn(PETSC_SUCCESS); 1939 } 1940 1941 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1942 { 1943 PetscDraw draw; 1944 DM cdm; 1945 PetscSection coordSection; 1946 Vec coordinates; 1947 PetscReal xyl[3], xyr[3]; 1948 PetscReal *refCoords, *edgeCoords; 1949 PetscBool isnull, drawAffine; 1950 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv, lineColor = PETSC_DETERMINE, cellColor = PETSC_DETERMINE; 1951 1952 PetscFunctionBegin; 1953 PetscCall(DMGetCoordinateDim(dm, &dim)); 1954 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1955 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1956 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1957 edgeDiv = cDegree + 1; 1958 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_line_color", &lineColor, NULL)); 1959 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_cell_color", &cellColor, NULL)); 1960 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1961 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1962 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1963 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1964 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1965 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1966 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1967 1968 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1969 PetscCall(PetscDrawIsNull(draw, &isnull)); 1970 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1971 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1972 1973 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1974 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1975 PetscCall(PetscDrawClear(draw)); 1976 1977 for (c = cStart; c < cEnd; ++c) { 1978 PetscScalar *coords = NULL; 1979 const PetscScalar *coords_arr; 1980 PetscInt numCoords; 1981 PetscBool isDG; 1982 1983 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1984 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, lineColor, cellColor, c, coords)); 1985 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1986 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1987 } 1988 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1989 PetscCall(PetscDrawFlush(draw)); 1990 PetscCall(PetscDrawPause(draw)); 1991 PetscCall(PetscDrawSave(draw)); 1992 PetscFunctionReturn(PETSC_SUCCESS); 1993 } 1994 1995 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1996 { 1997 DM odm = dm, rdm = dm, cdm; 1998 PetscFE fe; 1999 PetscSpace sp; 2000 PetscClassId id; 2001 PetscInt degree; 2002 PetscBool hoView = PETSC_TRUE; 2003 2004 PetscFunctionBegin; 2005 PetscObjectOptionsBegin((PetscObject)dm); 2006 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 2007 PetscOptionsEnd(); 2008 PetscCall(PetscObjectReference((PetscObject)dm)); 2009 *hdm = dm; 2010 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 2011 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2012 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 2013 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 2014 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 2015 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 2016 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 2017 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 2018 DM cdm, rcdm; 2019 Mat In; 2020 Vec cl, rcl; 2021 2022 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 2023 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, PETSC_FALSE)); 2024 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 2025 PetscCall(DMGetCoordinateDM(odm, &cdm)); 2026 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 2027 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 2028 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 2029 PetscCall(DMSetCoarseDM(rcdm, cdm)); 2030 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 2031 PetscCall(MatMult(In, cl, rcl)); 2032 PetscCall(MatDestroy(&In)); 2033 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 2034 PetscCall(DMDestroy(&odm)); 2035 odm = rdm; 2036 } 2037 *hdm = rdm; 2038 PetscFunctionReturn(PETSC_SUCCESS); 2039 } 2040 2041 #if defined(PETSC_HAVE_EXODUSII) 2042 #include <exodusII.h> 2043 #include <petscviewerexodusii.h> 2044 #endif 2045 2046 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 2047 { 2048 PetscBool isascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 2049 char name[PETSC_MAX_PATH_LEN]; 2050 2051 PetscFunctionBegin; 2052 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2053 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2054 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 2055 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2056 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2057 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2058 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 2059 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 2060 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 2061 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2062 if (isascii) { 2063 PetscViewerFormat format; 2064 PetscCall(PetscViewerGetFormat(viewer, &format)); 2065 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 2066 else PetscCall(DMPlexView_Ascii(dm, viewer)); 2067 } else if (ishdf5) { 2068 #if defined(PETSC_HAVE_HDF5) 2069 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 2070 #else 2071 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2072 #endif 2073 } else if (isvtk) { 2074 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2075 } else if (isdraw) { 2076 DM hdm; 2077 2078 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2079 PetscCall(DMPlexView_Draw(hdm, viewer)); 2080 PetscCall(DMDestroy(&hdm)); 2081 } else if (isglvis) { 2082 PetscCall(DMPlexView_GLVis(dm, viewer)); 2083 #if defined(PETSC_HAVE_EXODUSII) 2084 } else if (isexodus) { 2085 /* 2086 ExodusII requires that all sets be part of exactly one cell set. 2087 If the dm does not have a "Cell Sets" label defined, we create one 2088 with ID 1, containing all cells. 2089 Note that if the Cell Sets label is defined but does not cover all cells, 2090 we may still have a problem. This should probably be checked here or in the viewer; 2091 */ 2092 PetscInt numCS; 2093 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2094 if (!numCS) { 2095 PetscInt cStart, cEnd, c; 2096 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2097 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2098 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2099 } 2100 PetscCall(DMView_PlexExodusII(dm, viewer)); 2101 #endif 2102 #if defined(PETSC_HAVE_CGNS) 2103 } else if (iscgns) { 2104 PetscCall(DMView_PlexCGNS(dm, viewer)); 2105 #endif 2106 } else if (ispython) { 2107 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2108 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2109 /* Optionally view the partition */ 2110 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2111 if (flg) { 2112 Vec ranks; 2113 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2114 PetscCall(VecView(ranks, viewer)); 2115 PetscCall(VecDestroy(&ranks)); 2116 } 2117 /* Optionally view a label */ 2118 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2119 if (flg) { 2120 DMLabel label; 2121 Vec val; 2122 2123 PetscCall(DMGetLabel(dm, name, &label)); 2124 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2125 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2126 PetscCall(VecView(val, viewer)); 2127 PetscCall(VecDestroy(&val)); 2128 } 2129 PetscFunctionReturn(PETSC_SUCCESS); 2130 } 2131 2132 /*@ 2133 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2134 2135 Collective 2136 2137 Input Parameters: 2138 + dm - The `DM` whose topology is to be saved 2139 - viewer - The `PetscViewer` to save it in 2140 2141 Level: advanced 2142 2143 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2144 @*/ 2145 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2146 { 2147 PetscBool ishdf5; 2148 2149 PetscFunctionBegin; 2150 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2151 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2152 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2153 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2154 if (ishdf5) { 2155 #if defined(PETSC_HAVE_HDF5) 2156 IS globalPointNumbering; 2157 PetscViewerFormat format; 2158 2159 PetscCall(PetscViewerGetFormat(viewer, &format)); 2160 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2161 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2162 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2163 PetscCall(ISDestroy(&globalPointNumbering)); 2164 #else 2165 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2166 #endif 2167 } 2168 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2169 PetscFunctionReturn(PETSC_SUCCESS); 2170 } 2171 2172 /*@ 2173 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2174 2175 Collective 2176 2177 Input Parameters: 2178 + dm - The `DM` whose coordinates are to be saved 2179 - viewer - The `PetscViewer` for saving 2180 2181 Level: advanced 2182 2183 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2184 @*/ 2185 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2186 { 2187 PetscBool ishdf5; 2188 2189 PetscFunctionBegin; 2190 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2191 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2192 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2193 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2194 if (ishdf5) { 2195 #if defined(PETSC_HAVE_HDF5) 2196 PetscViewerFormat format; 2197 2198 PetscCall(PetscViewerGetFormat(viewer, &format)); 2199 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2200 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2201 #else 2202 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2203 #endif 2204 } 2205 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2206 PetscFunctionReturn(PETSC_SUCCESS); 2207 } 2208 2209 /*@ 2210 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2211 2212 Collective 2213 2214 Input Parameters: 2215 + dm - The `DM` whose labels are to be saved 2216 - viewer - The `PetscViewer` for saving 2217 2218 Level: advanced 2219 2220 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2221 @*/ 2222 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2223 { 2224 PetscBool ishdf5; 2225 2226 PetscFunctionBegin; 2227 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2228 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2229 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2230 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2231 if (ishdf5) { 2232 #if defined(PETSC_HAVE_HDF5) 2233 IS globalPointNumbering; 2234 PetscViewerFormat format; 2235 2236 PetscCall(PetscViewerGetFormat(viewer, &format)); 2237 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2238 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2239 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2240 PetscCall(ISDestroy(&globalPointNumbering)); 2241 #else 2242 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2243 #endif 2244 } 2245 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2246 PetscFunctionReturn(PETSC_SUCCESS); 2247 } 2248 2249 /*@ 2250 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2251 2252 Collective 2253 2254 Input Parameters: 2255 + dm - The `DM` that contains the topology on which the section to be saved is defined 2256 . viewer - The `PetscViewer` for saving 2257 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2258 2259 Level: advanced 2260 2261 Notes: 2262 This function is a wrapper around `PetscSectionView()`; in addition to the raw section, it saves information that associates the section points to the topology (`dm`) points. When the topology (`dm`) and the section are later loaded with `DMPlexTopologyLoad()` and `DMPlexSectionLoad()`, respectively, this information is used to match section points with topology points. 2263 2264 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2265 2266 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2267 @*/ 2268 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2269 { 2270 PetscBool ishdf5; 2271 2272 PetscFunctionBegin; 2273 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2274 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2275 if (!sectiondm) sectiondm = dm; 2276 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2277 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2278 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2279 if (ishdf5) { 2280 #if defined(PETSC_HAVE_HDF5) 2281 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2282 #else 2283 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2284 #endif 2285 } 2286 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2287 PetscFunctionReturn(PETSC_SUCCESS); 2288 } 2289 2290 /*@ 2291 DMPlexGlobalVectorView - Saves a global vector 2292 2293 Collective 2294 2295 Input Parameters: 2296 + dm - The `DM` that represents the topology 2297 . viewer - The `PetscViewer` to save data with 2298 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2299 - vec - The global vector to be saved 2300 2301 Level: advanced 2302 2303 Notes: 2304 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2305 2306 Calling sequence: 2307 .vb 2308 DMCreate(PETSC_COMM_WORLD, &dm); 2309 DMSetType(dm, DMPLEX); 2310 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2311 DMClone(dm, §iondm); 2312 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2313 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2314 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2315 PetscSectionSetChart(section, pStart, pEnd); 2316 PetscSectionSetUp(section); 2317 DMSetLocalSection(sectiondm, section); 2318 PetscSectionDestroy(§ion); 2319 DMGetGlobalVector(sectiondm, &vec); 2320 PetscObjectSetName((PetscObject)vec, "vec_name"); 2321 DMPlexTopologyView(dm, viewer); 2322 DMPlexSectionView(dm, viewer, sectiondm); 2323 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2324 DMRestoreGlobalVector(sectiondm, &vec); 2325 DMDestroy(§iondm); 2326 DMDestroy(&dm); 2327 .ve 2328 2329 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2330 @*/ 2331 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2332 { 2333 PetscBool ishdf5; 2334 2335 PetscFunctionBegin; 2336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2337 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2338 if (!sectiondm) sectiondm = dm; 2339 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2340 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2341 /* Check consistency */ 2342 { 2343 PetscSection section; 2344 PetscBool includesConstraints; 2345 PetscInt m, m1; 2346 2347 PetscCall(VecGetLocalSize(vec, &m1)); 2348 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2349 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2350 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2351 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2352 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2353 } 2354 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2355 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2356 if (ishdf5) { 2357 #if defined(PETSC_HAVE_HDF5) 2358 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2359 #else 2360 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2361 #endif 2362 } 2363 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2364 PetscFunctionReturn(PETSC_SUCCESS); 2365 } 2366 2367 /*@ 2368 DMPlexLocalVectorView - Saves a local vector 2369 2370 Collective 2371 2372 Input Parameters: 2373 + dm - The `DM` that represents the topology 2374 . viewer - The `PetscViewer` to save data with 2375 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2376 - vec - The local vector to be saved 2377 2378 Level: advanced 2379 2380 Note: 2381 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2382 2383 Calling sequence: 2384 .vb 2385 DMCreate(PETSC_COMM_WORLD, &dm); 2386 DMSetType(dm, DMPLEX); 2387 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2388 DMClone(dm, §iondm); 2389 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2390 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2391 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2392 PetscSectionSetChart(section, pStart, pEnd); 2393 PetscSectionSetUp(section); 2394 DMSetLocalSection(sectiondm, section); 2395 DMGetLocalVector(sectiondm, &vec); 2396 PetscObjectSetName((PetscObject)vec, "vec_name"); 2397 DMPlexTopologyView(dm, viewer); 2398 DMPlexSectionView(dm, viewer, sectiondm); 2399 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2400 DMRestoreLocalVector(sectiondm, &vec); 2401 DMDestroy(§iondm); 2402 DMDestroy(&dm); 2403 .ve 2404 2405 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2406 @*/ 2407 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2408 { 2409 PetscBool ishdf5; 2410 2411 PetscFunctionBegin; 2412 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2413 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2414 if (!sectiondm) sectiondm = dm; 2415 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2416 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2417 /* Check consistency */ 2418 { 2419 PetscSection section; 2420 PetscBool includesConstraints; 2421 PetscInt m, m1; 2422 2423 PetscCall(VecGetLocalSize(vec, &m1)); 2424 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2425 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2426 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2427 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2428 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2429 } 2430 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2431 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2432 if (ishdf5) { 2433 #if defined(PETSC_HAVE_HDF5) 2434 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2435 #else 2436 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2437 #endif 2438 } 2439 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2440 PetscFunctionReturn(PETSC_SUCCESS); 2441 } 2442 2443 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2444 { 2445 PetscBool ishdf5; 2446 2447 PetscFunctionBegin; 2448 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2449 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2450 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2451 if (ishdf5) { 2452 #if defined(PETSC_HAVE_HDF5) 2453 PetscViewerFormat format; 2454 PetscCall(PetscViewerGetFormat(viewer, &format)); 2455 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2456 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2457 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2458 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2459 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2460 PetscFunctionReturn(PETSC_SUCCESS); 2461 #else 2462 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2463 #endif 2464 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2465 } 2466 2467 /*@ 2468 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2469 2470 Collective 2471 2472 Input Parameters: 2473 + dm - The `DM` into which the topology is loaded 2474 - viewer - The `PetscViewer` for the saved topology 2475 2476 Output Parameter: 2477 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; 2478 `NULL` if unneeded 2479 2480 Level: advanced 2481 2482 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2483 `PetscViewer`, `PetscSF` 2484 @*/ 2485 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2486 { 2487 PetscBool ishdf5; 2488 2489 PetscFunctionBegin; 2490 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2491 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2492 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2493 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2494 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2495 if (ishdf5) { 2496 #if defined(PETSC_HAVE_HDF5) 2497 PetscViewerFormat format; 2498 2499 PetscCall(PetscViewerGetFormat(viewer, &format)); 2500 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2501 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2502 #else 2503 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2504 #endif 2505 } 2506 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2507 PetscFunctionReturn(PETSC_SUCCESS); 2508 } 2509 2510 /*@ 2511 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2512 2513 Collective 2514 2515 Input Parameters: 2516 + dm - The `DM` into which the coordinates are loaded 2517 . viewer - The `PetscViewer` for the saved coordinates 2518 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2519 2520 Level: advanced 2521 2522 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2523 `PetscSF`, `PetscViewer` 2524 @*/ 2525 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2526 { 2527 PetscBool ishdf5; 2528 2529 PetscFunctionBegin; 2530 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2531 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2532 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2533 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2534 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2535 if (ishdf5) { 2536 #if defined(PETSC_HAVE_HDF5) 2537 PetscViewerFormat format; 2538 2539 PetscCall(PetscViewerGetFormat(viewer, &format)); 2540 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2541 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2542 #else 2543 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2544 #endif 2545 } 2546 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2547 PetscFunctionReturn(PETSC_SUCCESS); 2548 } 2549 2550 /*@ 2551 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2552 2553 Collective 2554 2555 Input Parameters: 2556 + dm - The `DM` into which the labels are loaded 2557 . viewer - The `PetscViewer` for the saved labels 2558 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2559 2560 Level: advanced 2561 2562 Note: 2563 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2564 2565 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2566 `PetscSF`, `PetscViewer` 2567 @*/ 2568 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2569 { 2570 PetscBool ishdf5; 2571 2572 PetscFunctionBegin; 2573 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2574 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2575 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2576 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2577 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2578 if (ishdf5) { 2579 #if defined(PETSC_HAVE_HDF5) 2580 PetscViewerFormat format; 2581 2582 PetscCall(PetscViewerGetFormat(viewer, &format)); 2583 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2584 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2585 #else 2586 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2587 #endif 2588 } 2589 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2590 PetscFunctionReturn(PETSC_SUCCESS); 2591 } 2592 2593 /*@ 2594 DMPlexSectionLoad - Loads section into a `DMPLEX` 2595 2596 Collective 2597 2598 Input Parameters: 2599 + dm - The `DM` that represents the topology 2600 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2601 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2602 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2603 2604 Output Parameters: 2605 + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed) 2606 - localDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed) 2607 2608 Level: advanced 2609 2610 Notes: 2611 This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2612 2613 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2614 2615 The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2616 2617 Example using 2 processes: 2618 .vb 2619 NX (number of points on dm): 4 2620 sectionA : the on-disk section 2621 vecA : a vector associated with sectionA 2622 sectionB : sectiondm's local section constructed in this function 2623 vecB (local) : a vector associated with sectiondm's local section 2624 vecB (global) : a vector associated with sectiondm's global section 2625 2626 rank 0 rank 1 2627 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2628 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2629 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2630 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2631 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2632 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2633 sectionB->atlasDof : 1 0 1 | 1 3 2634 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2635 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2636 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2637 .ve 2638 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2639 2640 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2641 @*/ 2642 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, PeOp DM sectiondm, PetscSF globalToLocalPointSF, PeOp PetscSF *globalDofSF, PeOp PetscSF *localDofSF) 2643 { 2644 PetscBool ishdf5; 2645 2646 PetscFunctionBegin; 2647 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2648 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2649 if (!sectiondm) sectiondm = dm; 2650 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2651 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2652 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2653 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2654 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2655 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2656 if (ishdf5) { 2657 #if defined(PETSC_HAVE_HDF5) 2658 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2659 #else 2660 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2661 #endif 2662 } 2663 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2664 PetscFunctionReturn(PETSC_SUCCESS); 2665 } 2666 2667 /*@ 2668 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2669 2670 Collective 2671 2672 Input Parameters: 2673 + dm - The `DM` that represents the topology 2674 . viewer - The `PetscViewer` that represents the on-disk vector data 2675 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2676 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2677 - vec - The global vector to set values of 2678 2679 Level: advanced 2680 2681 Notes: 2682 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2683 2684 Calling sequence: 2685 .vb 2686 DMCreate(PETSC_COMM_WORLD, &dm); 2687 DMSetType(dm, DMPLEX); 2688 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2689 DMPlexTopologyLoad(dm, viewer, &sfX); 2690 DMClone(dm, §iondm); 2691 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2692 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2693 DMGetGlobalVector(sectiondm, &vec); 2694 PetscObjectSetName((PetscObject)vec, "vec_name"); 2695 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2696 DMRestoreGlobalVector(sectiondm, &vec); 2697 PetscSFDestroy(&gsf); 2698 PetscSFDestroy(&sfX); 2699 DMDestroy(§iondm); 2700 DMDestroy(&dm); 2701 .ve 2702 2703 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2704 `PetscSF`, `PetscViewer` 2705 @*/ 2706 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2707 { 2708 PetscBool ishdf5; 2709 2710 PetscFunctionBegin; 2711 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2712 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2713 if (!sectiondm) sectiondm = dm; 2714 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2715 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2716 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2717 /* Check consistency */ 2718 { 2719 PetscSection section; 2720 PetscBool includesConstraints; 2721 PetscInt m, m1; 2722 2723 PetscCall(VecGetLocalSize(vec, &m1)); 2724 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2725 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2726 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2727 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2728 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2729 } 2730 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2731 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2732 if (ishdf5) { 2733 #if defined(PETSC_HAVE_HDF5) 2734 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2735 #else 2736 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2737 #endif 2738 } 2739 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2740 PetscFunctionReturn(PETSC_SUCCESS); 2741 } 2742 2743 /*@ 2744 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2745 2746 Collective 2747 2748 Input Parameters: 2749 + dm - The `DM` that represents the topology 2750 . viewer - The `PetscViewer` that represents the on-disk vector data 2751 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2752 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2753 - vec - The local vector to set values of 2754 2755 Level: advanced 2756 2757 Notes: 2758 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2759 2760 Calling sequence: 2761 .vb 2762 DMCreate(PETSC_COMM_WORLD, &dm); 2763 DMSetType(dm, DMPLEX); 2764 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2765 DMPlexTopologyLoad(dm, viewer, &sfX); 2766 DMClone(dm, §iondm); 2767 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2768 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2769 DMGetLocalVector(sectiondm, &vec); 2770 PetscObjectSetName((PetscObject)vec, "vec_name"); 2771 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2772 DMRestoreLocalVector(sectiondm, &vec); 2773 PetscSFDestroy(&lsf); 2774 PetscSFDestroy(&sfX); 2775 DMDestroy(§iondm); 2776 DMDestroy(&dm); 2777 .ve 2778 2779 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2780 `PetscSF`, `PetscViewer` 2781 @*/ 2782 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2783 { 2784 PetscBool ishdf5; 2785 2786 PetscFunctionBegin; 2787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2788 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2789 if (!sectiondm) sectiondm = dm; 2790 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2791 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2792 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2793 /* Check consistency */ 2794 { 2795 PetscSection section; 2796 PetscBool includesConstraints; 2797 PetscInt m, m1; 2798 2799 PetscCall(VecGetLocalSize(vec, &m1)); 2800 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2801 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2802 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2803 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2804 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2805 } 2806 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2807 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2808 if (ishdf5) { 2809 #if defined(PETSC_HAVE_HDF5) 2810 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2811 #else 2812 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2813 #endif 2814 } 2815 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2816 PetscFunctionReturn(PETSC_SUCCESS); 2817 } 2818 2819 PetscErrorCode DMDestroy_Plex(DM dm) 2820 { 2821 DM_Plex *mesh = (DM_Plex *)dm->data; 2822 2823 PetscFunctionBegin; 2824 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2825 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2826 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2827 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBounds_C", NULL)); 2828 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2829 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2830 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2831 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2832 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2833 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2834 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2835 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2836 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2837 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2838 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2839 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2840 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2841 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2842 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2843 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2844 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2845 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2846 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2847 PetscCall(PetscFree(mesh->cones)); 2848 PetscCall(PetscFree(mesh->coneOrientations)); 2849 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2850 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2851 PetscCall(PetscFree(mesh->supports)); 2852 PetscCall(PetscFree(mesh->cellTypes)); 2853 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2854 PetscCall(PetscFree(mesh->tetgenOpts)); 2855 PetscCall(PetscFree(mesh->triangleOpts)); 2856 PetscCall(PetscFree(mesh->transformType)); 2857 PetscCall(PetscFree(mesh->distributionName)); 2858 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2859 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2860 PetscCall(ISDestroy(&mesh->subpointIS)); 2861 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2862 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2863 if (mesh->periodic.face_sfs) { 2864 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2865 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2866 } 2867 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2868 if (mesh->periodic.periodic_points) { 2869 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2870 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2871 } 2872 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2873 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2874 PetscCall(ISDestroy(&mesh->anchorIS)); 2875 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2876 PetscCall(PetscFree(mesh->parents)); 2877 PetscCall(PetscFree(mesh->childIDs)); 2878 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2879 PetscCall(PetscFree(mesh->children)); 2880 PetscCall(DMDestroy(&mesh->referenceTree)); 2881 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2882 PetscCall(PetscFree(mesh->neighbors)); 2883 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2884 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2885 PetscCall(DMPlexTransformDestroy(&mesh->transform)); 2886 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2887 PetscCall(PetscFree(mesh)); 2888 PetscFunctionReturn(PETSC_SUCCESS); 2889 } 2890 2891 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2892 { 2893 PetscSection sectionGlobal, sectionLocal; 2894 PetscInt bs = -1, mbs; 2895 PetscInt localSize, localStart = 0; 2896 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2897 MatType mtype; 2898 ISLocalToGlobalMapping ltog; 2899 2900 PetscFunctionBegin; 2901 PetscCall(MatInitializePackage()); 2902 mtype = dm->mattype; 2903 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2904 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2905 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2906 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2907 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2908 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2909 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2910 PetscCall(MatSetType(*J, mtype)); 2911 PetscCall(MatSetFromOptions(*J)); 2912 PetscCall(MatGetBlockSize(*J, &mbs)); 2913 if (mbs > 1) bs = mbs; 2914 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2915 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2916 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2917 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2918 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2919 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2920 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2921 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2922 if (!isShell) { 2923 // There are three states with pblocks, since block starts can have no dofs: 2924 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2925 // TRUE) Block Start: The first entry in a block has been added 2926 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2927 PetscBT blst; 2928 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2929 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2930 const PetscInt *perm = NULL; 2931 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2932 PetscInt pStart, pEnd, dof, cdof, num_fields; 2933 2934 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2935 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2936 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2937 2938 PetscCall(PetscCalloc1(localSize, &pblocks)); 2939 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2940 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2941 // We need to process in the permuted order to get block sizes right 2942 for (PetscInt point = pStart; point < pEnd; ++point) { 2943 const PetscInt p = perm ? perm[point] : point; 2944 2945 switch (dm->blocking_type) { 2946 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2947 PetscInt bdof, offset; 2948 2949 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2950 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2951 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2952 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2953 if (dof > 0) { 2954 // State change 2955 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2956 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2957 2958 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2959 // Signal block concatenation 2960 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2961 } 2962 dof = dof < 0 ? -(dof + 1) : dof; 2963 bdof = cdof && (dof - cdof) ? 1 : dof; 2964 if (dof) { 2965 if (bs < 0) { 2966 bs = bdof; 2967 } else if (bs != bdof) { 2968 bs = 1; 2969 } 2970 } 2971 } break; 2972 case DM_BLOCKING_FIELD_NODE: { 2973 for (PetscInt field = 0; field < num_fields; field++) { 2974 PetscInt num_comp, bdof, offset; 2975 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2976 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2977 if (dof < 0) continue; 2978 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2979 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2980 PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp); 2981 PetscInt num_nodes = dof / num_comp; 2982 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2983 // Handle possibly constant block size (unlikely) 2984 bdof = cdof && (dof - cdof) ? 1 : dof; 2985 if (dof) { 2986 if (bs < 0) { 2987 bs = bdof; 2988 } else if (bs != bdof) { 2989 bs = 1; 2990 } 2991 } 2992 } 2993 } break; 2994 } 2995 } 2996 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2997 /* Must have same blocksize on all procs (some might have no points) */ 2998 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 2999 bsLocal[1] = bs; 3000 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 3001 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 3002 else bs = bsMinMax[0]; 3003 bs = PetscMax(1, bs); 3004 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 3005 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 3006 PetscCall(MatSetBlockSize(*J, bs)); 3007 PetscCall(MatSetUp(*J)); 3008 } else { 3009 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 3010 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 3011 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 3012 } 3013 if (pblocks) { // Consolidate blocks 3014 PetscInt nblocks = 0; 3015 pblocks[0] = PetscAbs(pblocks[0]); 3016 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 3017 if (pblocks[i] == 0) continue; 3018 // Negative block size indicates the blocks should be concatenated 3019 if (pblocks[i] < 0) { 3020 pblocks[i] = -pblocks[i]; 3021 pblocks[nblocks - 1] += pblocks[i]; 3022 } else { 3023 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 3024 } 3025 for (PetscInt j = 1; j < pblocks[i]; j++) 3026 PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j); 3027 } 3028 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 3029 } 3030 PetscCall(PetscFree(pblocks)); 3031 } 3032 PetscCall(MatSetDM(*J, dm)); 3033 PetscFunctionReturn(PETSC_SUCCESS); 3034 } 3035 3036 /*@ 3037 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 3038 3039 Not Collective 3040 3041 Input Parameter: 3042 . dm - The `DMPLEX` 3043 3044 Output Parameter: 3045 . subsection - The subdomain section 3046 3047 Level: developer 3048 3049 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 3050 @*/ 3051 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 3052 { 3053 DM_Plex *mesh = (DM_Plex *)dm->data; 3054 3055 PetscFunctionBegin; 3056 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3057 if (!mesh->subdomainSection) { 3058 PetscSection section; 3059 PetscSF sf; 3060 3061 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 3062 PetscCall(DMGetLocalSection(dm, §ion)); 3063 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 3064 PetscCall(PetscSFDestroy(&sf)); 3065 } 3066 *subsection = mesh->subdomainSection; 3067 PetscFunctionReturn(PETSC_SUCCESS); 3068 } 3069 3070 /*@ 3071 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 3072 3073 Not Collective 3074 3075 Input Parameter: 3076 . dm - The `DMPLEX` 3077 3078 Output Parameters: 3079 + pStart - The first mesh point 3080 - pEnd - The upper bound for mesh points 3081 3082 Level: beginner 3083 3084 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3085 @*/ 3086 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3087 { 3088 DM_Plex *mesh = (DM_Plex *)dm->data; 3089 3090 PetscFunctionBegin; 3091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3092 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3093 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3094 PetscFunctionReturn(PETSC_SUCCESS); 3095 } 3096 3097 /*@ 3098 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3099 3100 Not Collective 3101 3102 Input Parameters: 3103 + dm - The `DMPLEX` 3104 . pStart - The first mesh point 3105 - pEnd - The upper bound for mesh points 3106 3107 Level: beginner 3108 3109 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3110 @*/ 3111 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3112 { 3113 DM_Plex *mesh = (DM_Plex *)dm->data; 3114 3115 PetscFunctionBegin; 3116 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3117 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3118 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3119 PetscCall(PetscFree(mesh->cellTypes)); 3120 PetscFunctionReturn(PETSC_SUCCESS); 3121 } 3122 3123 /*@ 3124 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3125 3126 Not Collective 3127 3128 Input Parameters: 3129 + dm - The `DMPLEX` 3130 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3131 3132 Output Parameter: 3133 . size - The cone size for point `p` 3134 3135 Level: beginner 3136 3137 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3138 @*/ 3139 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3140 { 3141 DM_Plex *mesh = (DM_Plex *)dm->data; 3142 3143 PetscFunctionBegin; 3144 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3145 PetscAssertPointer(size, 3); 3146 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3147 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3148 PetscFunctionReturn(PETSC_SUCCESS); 3149 } 3150 3151 /*@ 3152 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3153 3154 Not Collective 3155 3156 Input Parameters: 3157 + dm - The `DMPLEX` 3158 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3159 - size - The cone size for point `p` 3160 3161 Level: beginner 3162 3163 Note: 3164 This should be called after `DMPlexSetChart()`. 3165 3166 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3167 @*/ 3168 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3169 { 3170 DM_Plex *mesh = (DM_Plex *)dm->data; 3171 3172 PetscFunctionBegin; 3173 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3174 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3175 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3176 PetscFunctionReturn(PETSC_SUCCESS); 3177 } 3178 3179 /*@C 3180 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3181 3182 Not Collective 3183 3184 Input Parameters: 3185 + dm - The `DMPLEX` 3186 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3187 3188 Output Parameter: 3189 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3190 3191 Level: beginner 3192 3193 Fortran Notes: 3194 `cone` must be declared with 3195 .vb 3196 PetscInt, pointer :: cone(:) 3197 .ve 3198 3199 You must call `DMPlexRestoreCone()` after you finish using the array. 3200 `DMPlexRestoreCone()` is not needed/available in C. 3201 3202 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3203 @*/ 3204 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3205 { 3206 DM_Plex *mesh = (DM_Plex *)dm->data; 3207 PetscInt off; 3208 3209 PetscFunctionBegin; 3210 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3211 PetscAssertPointer(cone, 3); 3212 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3213 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3214 PetscFunctionReturn(PETSC_SUCCESS); 3215 } 3216 3217 /*@ 3218 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3219 3220 Not Collective 3221 3222 Input Parameters: 3223 + dm - The `DMPLEX` 3224 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3225 3226 Output Parameters: 3227 + pConesSection - `PetscSection` describing the layout of `pCones` 3228 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3229 3230 Level: intermediate 3231 3232 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3233 @*/ 3234 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PeOp PetscSection *pConesSection, PeOp IS *pCones) 3235 { 3236 PetscSection cs, newcs; 3237 PetscInt *cones; 3238 PetscInt *newarr = NULL; 3239 PetscInt n; 3240 3241 PetscFunctionBegin; 3242 PetscCall(DMPlexGetCones(dm, &cones)); 3243 PetscCall(DMPlexGetConeSection(dm, &cs)); 3244 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3245 if (pConesSection) *pConesSection = newcs; 3246 if (pCones) { 3247 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3248 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3249 } 3250 PetscFunctionReturn(PETSC_SUCCESS); 3251 } 3252 3253 /*@ 3254 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3255 3256 Not Collective 3257 3258 Input Parameters: 3259 + dm - The `DMPLEX` 3260 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3261 3262 Output Parameter: 3263 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3264 3265 Level: advanced 3266 3267 Notes: 3268 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3269 3270 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3271 3272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3273 `DMPlexGetDepth()`, `IS` 3274 @*/ 3275 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3276 { 3277 IS *expandedPointsAll; 3278 PetscInt depth; 3279 3280 PetscFunctionBegin; 3281 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3282 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3283 PetscAssertPointer(expandedPoints, 3); 3284 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3285 *expandedPoints = expandedPointsAll[0]; 3286 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3287 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3288 PetscFunctionReturn(PETSC_SUCCESS); 3289 } 3290 3291 /*@ 3292 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3293 (DAG points of depth 0, i.e., without cones). 3294 3295 Not Collective 3296 3297 Input Parameters: 3298 + dm - The `DMPLEX` 3299 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3300 3301 Output Parameters: 3302 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3303 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3304 - sections - (optional) An array of sections which describe mappings from points to their cone points 3305 3306 Level: advanced 3307 3308 Notes: 3309 Like `DMPlexGetConeTuple()` but recursive. 3310 3311 Array `expandedPoints` has size equal to `depth`. Each `expandedPoints`[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 3312 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3313 3314 Array section has size equal to `depth`. Each `PetscSection` `sections`[d] realizes mapping from `expandedPoints`[d+1] (section points) to `expandedPoints`[d] (section dofs) as follows\: 3315 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3316 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3317 3318 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3319 `DMPlexGetDepth()`, `PetscSection`, `IS` 3320 @*/ 3321 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3322 { 3323 const PetscInt *arr0 = NULL, *cone = NULL; 3324 PetscInt *arr = NULL, *newarr = NULL; 3325 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3326 IS *expandedPoints_; 3327 PetscSection *sections_; 3328 3329 PetscFunctionBegin; 3330 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3331 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3332 if (depth) PetscAssertPointer(depth, 3); 3333 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3334 if (sections) PetscAssertPointer(sections, 5); 3335 PetscCall(ISGetLocalSize(points, &n)); 3336 PetscCall(ISGetIndices(points, &arr0)); 3337 PetscCall(DMPlexGetDepth(dm, &depth_)); 3338 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3339 PetscCall(PetscCalloc1(depth_, §ions_)); 3340 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3341 for (d = depth_ - 1; d >= 0; d--) { 3342 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3343 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3344 for (i = 0; i < n; i++) { 3345 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3346 if (arr[i] >= start && arr[i] < end) { 3347 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3348 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3349 } else { 3350 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3351 } 3352 } 3353 PetscCall(PetscSectionSetUp(sections_[d])); 3354 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3355 PetscCall(PetscMalloc1(newn, &newarr)); 3356 for (i = 0; i < n; i++) { 3357 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3358 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3359 if (cn > 1) { 3360 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3361 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3362 } else { 3363 newarr[co] = arr[i]; 3364 } 3365 } 3366 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3367 arr = newarr; 3368 n = newn; 3369 } 3370 PetscCall(ISRestoreIndices(points, &arr0)); 3371 *depth = depth_; 3372 if (expandedPoints) *expandedPoints = expandedPoints_; 3373 else { 3374 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3375 PetscCall(PetscFree(expandedPoints_)); 3376 } 3377 if (sections) *sections = sections_; 3378 else { 3379 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3380 PetscCall(PetscFree(sections_)); 3381 } 3382 PetscFunctionReturn(PETSC_SUCCESS); 3383 } 3384 3385 /*@ 3386 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3387 3388 Not Collective 3389 3390 Input Parameters: 3391 + dm - The `DMPLEX` 3392 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3393 3394 Output Parameters: 3395 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3396 . expandedPoints - (optional) An array of recursively expanded cones 3397 - sections - (optional) An array of sections which describe mappings from points to their cone points 3398 3399 Level: advanced 3400 3401 Note: 3402 See `DMPlexGetConeRecursive()` 3403 3404 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3405 `DMPlexGetDepth()`, `IS`, `PetscSection` 3406 @*/ 3407 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3408 { 3409 PetscInt d, depth_; 3410 3411 PetscFunctionBegin; 3412 PetscCall(DMPlexGetDepth(dm, &depth_)); 3413 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3414 if (depth) *depth = 0; 3415 if (expandedPoints) { 3416 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3417 PetscCall(PetscFree(*expandedPoints)); 3418 } 3419 if (sections) { 3420 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3421 PetscCall(PetscFree(*sections)); 3422 } 3423 PetscFunctionReturn(PETSC_SUCCESS); 3424 } 3425 3426 /*@ 3427 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 3428 3429 Not Collective 3430 3431 Input Parameters: 3432 + dm - The `DMPLEX` 3433 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3434 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3435 3436 Level: beginner 3437 3438 Note: 3439 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3440 3441 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3442 @*/ 3443 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3444 { 3445 DM_Plex *mesh = (DM_Plex *)dm->data; 3446 PetscInt dof, off, c; 3447 3448 PetscFunctionBegin; 3449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3450 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3451 if (dof) PetscAssertPointer(cone, 3); 3452 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3453 if (PetscDefined(USE_DEBUG)) { 3454 PetscInt pStart, pEnd; 3455 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3456 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3457 for (c = 0; c < dof; ++c) { 3458 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3459 mesh->cones[off + c] = cone[c]; 3460 } 3461 } else { 3462 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3463 } 3464 PetscFunctionReturn(PETSC_SUCCESS); 3465 } 3466 3467 /*@C 3468 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3469 3470 Not Collective 3471 3472 Input Parameters: 3473 + dm - The `DMPLEX` 3474 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3475 3476 Output Parameter: 3477 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3478 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3479 3480 Level: beginner 3481 3482 Note: 3483 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3484 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3485 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3486 with the identity. 3487 3488 Fortran Notes: 3489 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3490 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3491 3492 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3493 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3494 @*/ 3495 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3496 { 3497 DM_Plex *mesh = (DM_Plex *)dm->data; 3498 PetscInt off; 3499 3500 PetscFunctionBegin; 3501 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3502 if (PetscDefined(USE_DEBUG)) { 3503 PetscInt dof; 3504 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3505 if (dof) PetscAssertPointer(coneOrientation, 3); 3506 } 3507 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3508 3509 *coneOrientation = &mesh->coneOrientations[off]; 3510 PetscFunctionReturn(PETSC_SUCCESS); 3511 } 3512 3513 /*@ 3514 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3515 3516 Not Collective 3517 3518 Input Parameters: 3519 + dm - The `DMPLEX` 3520 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3521 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3522 3523 Level: beginner 3524 3525 Notes: 3526 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3527 3528 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3529 3530 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3531 @*/ 3532 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3533 { 3534 DM_Plex *mesh = (DM_Plex *)dm->data; 3535 PetscInt pStart, pEnd; 3536 PetscInt dof, off, c; 3537 3538 PetscFunctionBegin; 3539 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3540 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3541 if (dof) PetscAssertPointer(coneOrientation, 3); 3542 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3543 if (PetscDefined(USE_DEBUG)) { 3544 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3545 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3546 for (c = 0; c < dof; ++c) { 3547 PetscInt cdof, o = coneOrientation[c]; 3548 3549 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3550 PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof); 3551 mesh->coneOrientations[off + c] = o; 3552 } 3553 } else { 3554 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3555 } 3556 PetscFunctionReturn(PETSC_SUCCESS); 3557 } 3558 3559 /*@ 3560 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3561 3562 Not Collective 3563 3564 Input Parameters: 3565 + dm - The `DMPLEX` 3566 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3567 . conePos - The local index in the cone where the point should be put 3568 - conePoint - The mesh point to insert 3569 3570 Level: beginner 3571 3572 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3573 @*/ 3574 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3575 { 3576 DM_Plex *mesh = (DM_Plex *)dm->data; 3577 PetscInt pStart, pEnd; 3578 PetscInt dof, off; 3579 3580 PetscFunctionBegin; 3581 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3582 if (PetscDefined(USE_DEBUG)) { 3583 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3584 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3585 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3586 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3587 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3588 } 3589 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3590 mesh->cones[off + conePos] = conePoint; 3591 PetscFunctionReturn(PETSC_SUCCESS); 3592 } 3593 3594 /*@ 3595 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3596 3597 Not Collective 3598 3599 Input Parameters: 3600 + dm - The `DMPLEX` 3601 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3602 . conePos - The local index in the cone where the point should be put 3603 - coneOrientation - The point orientation to insert 3604 3605 Level: beginner 3606 3607 Note: 3608 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3609 3610 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3611 @*/ 3612 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3613 { 3614 DM_Plex *mesh = (DM_Plex *)dm->data; 3615 PetscInt pStart, pEnd; 3616 PetscInt dof, off; 3617 3618 PetscFunctionBegin; 3619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3620 if (PetscDefined(USE_DEBUG)) { 3621 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3622 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3623 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3624 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3625 } 3626 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3627 mesh->coneOrientations[off + conePos] = coneOrientation; 3628 PetscFunctionReturn(PETSC_SUCCESS); 3629 } 3630 3631 /*@C 3632 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3633 3634 Not collective 3635 3636 Input Parameters: 3637 + dm - The DMPlex 3638 - p - The point, which must lie in the chart set with DMPlexSetChart() 3639 3640 Output Parameters: 3641 + cone - An array of points which are on the in-edges for point `p` 3642 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3643 integer giving the prescription for cone traversal. 3644 3645 Level: beginner 3646 3647 Notes: 3648 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3649 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3650 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3651 with the identity. 3652 3653 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3654 3655 Fortran Notes: 3656 `cone` and `ornt` must be declared with 3657 .vb 3658 PetscInt, pointer :: cone(:) 3659 PetscInt, pointer :: ornt(:) 3660 .ve 3661 3662 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3663 @*/ 3664 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, PeOp const PetscInt *cone[], PeOp const PetscInt *ornt[]) 3665 { 3666 DM_Plex *mesh = (DM_Plex *)dm->data; 3667 3668 PetscFunctionBegin; 3669 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3670 if (mesh->tr) { 3671 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3672 } else { 3673 PetscInt off; 3674 if (PetscDefined(USE_DEBUG)) { 3675 PetscInt dof; 3676 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3677 if (dof) { 3678 if (cone) PetscAssertPointer(cone, 3); 3679 if (ornt) PetscAssertPointer(ornt, 4); 3680 } 3681 } 3682 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3683 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3684 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3685 } 3686 PetscFunctionReturn(PETSC_SUCCESS); 3687 } 3688 3689 /*@C 3690 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3691 3692 Not Collective 3693 3694 Input Parameters: 3695 + dm - The DMPlex 3696 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3697 . cone - An array of points which are on the in-edges for point p 3698 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3699 integer giving the prescription for cone traversal. 3700 3701 Level: beginner 3702 3703 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3704 @*/ 3705 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3706 { 3707 DM_Plex *mesh = (DM_Plex *)dm->data; 3708 3709 PetscFunctionBegin; 3710 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3711 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3712 PetscFunctionReturn(PETSC_SUCCESS); 3713 } 3714 3715 /*@ 3716 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3717 3718 Not Collective 3719 3720 Input Parameters: 3721 + dm - The `DMPLEX` 3722 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3723 3724 Output Parameter: 3725 . size - The support size for point `p` 3726 3727 Level: beginner 3728 3729 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3730 @*/ 3731 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3732 { 3733 DM_Plex *mesh = (DM_Plex *)dm->data; 3734 3735 PetscFunctionBegin; 3736 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3737 PetscAssertPointer(size, 3); 3738 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3739 PetscFunctionReturn(PETSC_SUCCESS); 3740 } 3741 3742 /*@ 3743 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3744 3745 Not Collective 3746 3747 Input Parameters: 3748 + dm - The `DMPLEX` 3749 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3750 - size - The support size for point `p` 3751 3752 Level: beginner 3753 3754 Note: 3755 This should be called after `DMPlexSetChart()`. 3756 3757 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3758 @*/ 3759 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3760 { 3761 DM_Plex *mesh = (DM_Plex *)dm->data; 3762 3763 PetscFunctionBegin; 3764 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3765 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3766 PetscFunctionReturn(PETSC_SUCCESS); 3767 } 3768 3769 /*@C 3770 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3771 3772 Not Collective 3773 3774 Input Parameters: 3775 + dm - The `DMPLEX` 3776 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3777 3778 Output Parameter: 3779 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3780 3781 Level: beginner 3782 3783 Fortran Notes: 3784 `support` must be declared with 3785 .vb 3786 PetscInt, pointer :: support(:) 3787 .ve 3788 3789 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3790 `DMPlexRestoreSupport()` is not needed/available in C. 3791 3792 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3793 @*/ 3794 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3795 { 3796 DM_Plex *mesh = (DM_Plex *)dm->data; 3797 PetscInt off; 3798 3799 PetscFunctionBegin; 3800 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3801 PetscAssertPointer(support, 3); 3802 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3803 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3804 PetscFunctionReturn(PETSC_SUCCESS); 3805 } 3806 3807 /*@ 3808 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3809 3810 Not Collective 3811 3812 Input Parameters: 3813 + dm - The `DMPLEX` 3814 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3815 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3816 3817 Level: beginner 3818 3819 Note: 3820 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3821 3822 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3823 @*/ 3824 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3825 { 3826 DM_Plex *mesh = (DM_Plex *)dm->data; 3827 PetscInt pStart, pEnd; 3828 PetscInt dof, off, c; 3829 3830 PetscFunctionBegin; 3831 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3832 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3833 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3834 if (dof) PetscAssertPointer(support, 3); 3835 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3836 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3837 for (c = 0; c < dof; ++c) { 3838 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3839 mesh->supports[off + c] = support[c]; 3840 } 3841 PetscFunctionReturn(PETSC_SUCCESS); 3842 } 3843 3844 /*@ 3845 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3846 3847 Not Collective 3848 3849 Input Parameters: 3850 + dm - The `DMPLEX` 3851 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3852 . supportPos - The local index in the cone where the point should be put 3853 - supportPoint - The mesh point to insert 3854 3855 Level: beginner 3856 3857 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3858 @*/ 3859 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3860 { 3861 DM_Plex *mesh = (DM_Plex *)dm->data; 3862 PetscInt pStart, pEnd; 3863 PetscInt dof, off; 3864 3865 PetscFunctionBegin; 3866 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3867 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3868 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3869 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3870 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3871 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3872 PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3873 mesh->supports[off + supportPos] = supportPoint; 3874 PetscFunctionReturn(PETSC_SUCCESS); 3875 } 3876 3877 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3878 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3879 { 3880 switch (ct) { 3881 case DM_POLYTOPE_SEGMENT: 3882 if (o == -1) return -2; 3883 break; 3884 case DM_POLYTOPE_TRIANGLE: 3885 if (o == -3) return -1; 3886 if (o == -2) return -3; 3887 if (o == -1) return -2; 3888 break; 3889 case DM_POLYTOPE_QUADRILATERAL: 3890 if (o == -4) return -2; 3891 if (o == -3) return -1; 3892 if (o == -2) return -4; 3893 if (o == -1) return -3; 3894 break; 3895 default: 3896 return o; 3897 } 3898 return o; 3899 } 3900 3901 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3902 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3903 { 3904 switch (ct) { 3905 case DM_POLYTOPE_SEGMENT: 3906 if ((o == -2) || (o == 1)) return -1; 3907 if (o == -1) return 0; 3908 break; 3909 case DM_POLYTOPE_TRIANGLE: 3910 if (o == -3) return -2; 3911 if (o == -2) return -1; 3912 if (o == -1) return -3; 3913 break; 3914 case DM_POLYTOPE_QUADRILATERAL: 3915 if (o == -4) return -2; 3916 if (o == -3) return -1; 3917 if (o == -2) return -4; 3918 if (o == -1) return -3; 3919 break; 3920 default: 3921 return o; 3922 } 3923 return o; 3924 } 3925 3926 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3927 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3928 { 3929 PetscInt pStart, pEnd, p; 3930 3931 PetscFunctionBegin; 3932 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3933 for (p = pStart; p < pEnd; ++p) { 3934 const PetscInt *cone, *ornt; 3935 PetscInt coneSize, c; 3936 3937 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3938 PetscCall(DMPlexGetCone(dm, p, &cone)); 3939 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3940 for (c = 0; c < coneSize; ++c) { 3941 DMPolytopeType ct; 3942 const PetscInt o = ornt[c]; 3943 3944 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3945 switch (ct) { 3946 case DM_POLYTOPE_SEGMENT: 3947 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3948 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3949 break; 3950 case DM_POLYTOPE_TRIANGLE: 3951 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3952 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3953 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3954 break; 3955 case DM_POLYTOPE_QUADRILATERAL: 3956 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3957 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3958 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3959 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3960 break; 3961 default: 3962 break; 3963 } 3964 } 3965 } 3966 PetscFunctionReturn(PETSC_SUCCESS); 3967 } 3968 3969 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3970 { 3971 DM_Plex *mesh = (DM_Plex *)dm->data; 3972 3973 PetscFunctionBeginHot; 3974 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3975 if (useCone) { 3976 PetscCall(DMPlexGetConeSize(dm, p, size)); 3977 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3978 } else { 3979 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3980 PetscCall(DMPlexGetSupport(dm, p, arr)); 3981 } 3982 } else { 3983 if (useCone) { 3984 const PetscSection s = mesh->coneSection; 3985 const PetscInt ps = p - s->pStart; 3986 const PetscInt off = s->atlasOff[ps]; 3987 3988 *size = s->atlasDof[ps]; 3989 *arr = mesh->cones + off; 3990 *ornt = mesh->coneOrientations + off; 3991 } else { 3992 const PetscSection s = mesh->supportSection; 3993 const PetscInt ps = p - s->pStart; 3994 const PetscInt off = s->atlasOff[ps]; 3995 3996 *size = s->atlasDof[ps]; 3997 *arr = mesh->supports + off; 3998 } 3999 } 4000 PetscFunctionReturn(PETSC_SUCCESS); 4001 } 4002 4003 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 4004 { 4005 DM_Plex *mesh = (DM_Plex *)dm->data; 4006 4007 PetscFunctionBeginHot; 4008 if (PetscDefined(USE_DEBUG) || mesh->tr) { 4009 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 4010 } 4011 PetscFunctionReturn(PETSC_SUCCESS); 4012 } 4013 4014 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4015 { 4016 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4017 PetscInt *closure; 4018 const PetscInt *tmp = NULL, *tmpO = NULL; 4019 PetscInt off = 0, tmpSize, t; 4020 4021 PetscFunctionBeginHot; 4022 if (ornt) { 4023 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4024 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 4025 } 4026 if (*points) { 4027 closure = *points; 4028 } else { 4029 PetscInt maxConeSize, maxSupportSize; 4030 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4031 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 4032 } 4033 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4034 if (ct == DM_POLYTOPE_UNKNOWN) { 4035 closure[off++] = p; 4036 closure[off++] = 0; 4037 for (t = 0; t < tmpSize; ++t) { 4038 closure[off++] = tmp[t]; 4039 closure[off++] = tmpO ? tmpO[t] : 0; 4040 } 4041 } else { 4042 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 4043 4044 /* We assume that cells with a valid type have faces with a valid type */ 4045 closure[off++] = p; 4046 closure[off++] = ornt; 4047 for (t = 0; t < tmpSize; ++t) { 4048 DMPolytopeType ft; 4049 4050 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 4051 closure[off++] = tmp[arr[t]]; 4052 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 4053 } 4054 } 4055 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4056 if (numPoints) *numPoints = tmpSize + 1; 4057 if (points) *points = closure; 4058 PetscFunctionReturn(PETSC_SUCCESS); 4059 } 4060 4061 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 4062 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 4063 { 4064 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 4065 const PetscInt *cone, *ornt; 4066 PetscInt *pts, *closure = NULL; 4067 DMPolytopeType ft; 4068 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 4069 PetscInt dim, coneSize, c, d, clSize, cl; 4070 4071 PetscFunctionBeginHot; 4072 PetscCall(DMGetDimension(dm, &dim)); 4073 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4074 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4075 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4076 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4077 maxSize = PetscMax(coneSeries, supportSeries); 4078 if (*points) { 4079 pts = *points; 4080 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4081 c = 0; 4082 pts[c++] = point; 4083 pts[c++] = o; 4084 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4085 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4086 for (cl = 0; cl < clSize * 2; cl += 2) { 4087 pts[c++] = closure[cl]; 4088 pts[c++] = closure[cl + 1]; 4089 } 4090 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4091 for (cl = 0; cl < clSize * 2; cl += 2) { 4092 pts[c++] = closure[cl]; 4093 pts[c++] = closure[cl + 1]; 4094 } 4095 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4096 for (d = 2; d < coneSize; ++d) { 4097 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4098 pts[c++] = cone[arr[d * 2 + 0]]; 4099 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4100 } 4101 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4102 if (dim >= 3) { 4103 for (d = 2; d < coneSize; ++d) { 4104 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4105 const PetscInt *fcone, *fornt; 4106 PetscInt fconeSize, fc, i; 4107 4108 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4109 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4110 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4111 for (fc = 0; fc < fconeSize; ++fc) { 4112 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4113 const PetscInt co = farr[fc * 2 + 1]; 4114 4115 for (i = 0; i < c; i += 2) 4116 if (pts[i] == cp) break; 4117 if (i == c) { 4118 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4119 pts[c++] = cp; 4120 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4121 } 4122 } 4123 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4124 } 4125 } 4126 *numPoints = c / 2; 4127 *points = pts; 4128 PetscFunctionReturn(PETSC_SUCCESS); 4129 } 4130 4131 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4132 { 4133 DMPolytopeType ct; 4134 PetscInt *closure, *fifo; 4135 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4136 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4137 PetscInt depth, maxSize; 4138 4139 PetscFunctionBeginHot; 4140 PetscCall(DMPlexGetDepth(dm, &depth)); 4141 if (depth == 1) { 4142 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4143 PetscFunctionReturn(PETSC_SUCCESS); 4144 } 4145 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4146 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 4147 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4148 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4149 PetscFunctionReturn(PETSC_SUCCESS); 4150 } 4151 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4152 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4153 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4154 maxSize = PetscMax(coneSeries, supportSeries); 4155 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4156 if (*points) { 4157 closure = *points; 4158 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4159 closure[closureSize++] = p; 4160 closure[closureSize++] = ornt; 4161 fifo[fifoSize++] = p; 4162 fifo[fifoSize++] = ornt; 4163 fifo[fifoSize++] = ct; 4164 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4165 while (fifoSize - fifoStart) { 4166 const PetscInt q = fifo[fifoStart++]; 4167 const PetscInt o = fifo[fifoStart++]; 4168 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4169 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4170 const PetscInt *tmp, *tmpO = NULL; 4171 PetscInt tmpSize, t; 4172 4173 if (PetscDefined(USE_DEBUG)) { 4174 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4175 PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 4176 } 4177 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4178 for (t = 0; t < tmpSize; ++t) { 4179 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4180 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4181 const PetscInt cp = tmp[ip]; 4182 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4183 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4184 PetscInt c; 4185 4186 /* Check for duplicate */ 4187 for (c = 0; c < closureSize; c += 2) { 4188 if (closure[c] == cp) break; 4189 } 4190 if (c == closureSize) { 4191 closure[closureSize++] = cp; 4192 closure[closureSize++] = co; 4193 fifo[fifoSize++] = cp; 4194 fifo[fifoSize++] = co; 4195 fifo[fifoSize++] = ct; 4196 } 4197 } 4198 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4199 } 4200 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4201 if (numPoints) *numPoints = closureSize / 2; 4202 if (points) *points = closure; 4203 PetscFunctionReturn(PETSC_SUCCESS); 4204 } 4205 4206 /*@C 4207 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4208 4209 Not Collective 4210 4211 Input Parameters: 4212 + dm - The `DMPLEX` 4213 . p - The mesh point 4214 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4215 4216 Input/Output Parameter: 4217 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4218 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4219 otherwise the provided array is used to hold the values 4220 4221 Output Parameter: 4222 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4223 4224 Level: beginner 4225 4226 Note: 4227 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4228 4229 Fortran Notes: 4230 `points` must be declared with 4231 .vb 4232 PetscInt, pointer :: points(:) 4233 .ve 4234 and is always allocated by the function. 4235 4236 Pass `PETSC_NULL_INTEGER` for `numPoints` if it is not needed 4237 4238 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4239 @*/ 4240 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4241 { 4242 PetscFunctionBeginHot; 4243 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4244 if (numPoints) PetscAssertPointer(numPoints, 4); 4245 if (points) PetscAssertPointer(points, 5); 4246 if (PetscDefined(USE_DEBUG)) { 4247 PetscInt pStart, pEnd; 4248 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4249 PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 4250 } 4251 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4252 PetscFunctionReturn(PETSC_SUCCESS); 4253 } 4254 4255 /*@C 4256 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4257 4258 Not Collective 4259 4260 Input Parameters: 4261 + dm - The `DMPLEX` 4262 . p - The mesh point 4263 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4264 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4265 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4266 4267 Level: beginner 4268 4269 Note: 4270 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4271 4272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4273 @*/ 4274 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4275 { 4276 PetscFunctionBeginHot; 4277 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4278 if (numPoints) *numPoints = 0; 4279 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4280 PetscFunctionReturn(PETSC_SUCCESS); 4281 } 4282 4283 /*@ 4284 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4285 4286 Not Collective 4287 4288 Input Parameter: 4289 . dm - The `DMPLEX` 4290 4291 Output Parameters: 4292 + maxConeSize - The maximum number of in-edges 4293 - maxSupportSize - The maximum number of out-edges 4294 4295 Level: beginner 4296 4297 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4298 @*/ 4299 PetscErrorCode DMPlexGetMaxSizes(DM dm, PeOp PetscInt *maxConeSize, PeOp PetscInt *maxSupportSize) 4300 { 4301 DM_Plex *mesh = (DM_Plex *)dm->data; 4302 4303 PetscFunctionBegin; 4304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4305 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4306 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4307 PetscFunctionReturn(PETSC_SUCCESS); 4308 } 4309 4310 PetscErrorCode DMSetUp_Plex(DM dm) 4311 { 4312 DM_Plex *mesh = (DM_Plex *)dm->data; 4313 PetscInt size, maxSupportSize; 4314 4315 PetscFunctionBegin; 4316 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4317 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4318 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4319 PetscCall(PetscMalloc1(size, &mesh->cones)); 4320 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4321 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4322 if (maxSupportSize) { 4323 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4324 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4325 PetscCall(PetscMalloc1(size, &mesh->supports)); 4326 } 4327 PetscFunctionReturn(PETSC_SUCCESS); 4328 } 4329 4330 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4331 { 4332 PetscFunctionBegin; 4333 if (subdm) PetscCall(DMClone(dm, subdm)); 4334 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4335 if (subdm) (*subdm)->useNatural = dm->useNatural; 4336 if (dm->useNatural && dm->sfMigration) { 4337 PetscSF sfNatural; 4338 4339 (*subdm)->sfMigration = dm->sfMigration; 4340 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4341 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4342 (*subdm)->sfNatural = sfNatural; 4343 } 4344 PetscFunctionReturn(PETSC_SUCCESS); 4345 } 4346 4347 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4348 { 4349 PetscInt i = 0; 4350 4351 PetscFunctionBegin; 4352 PetscCall(DMClone(dms[0], superdm)); 4353 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4354 (*superdm)->useNatural = PETSC_FALSE; 4355 for (i = 0; i < len; i++) { 4356 if (dms[i]->useNatural && dms[i]->sfMigration) { 4357 PetscSF sfNatural; 4358 4359 (*superdm)->sfMigration = dms[i]->sfMigration; 4360 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4361 (*superdm)->useNatural = PETSC_TRUE; 4362 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4363 (*superdm)->sfNatural = sfNatural; 4364 break; 4365 } 4366 } 4367 PetscFunctionReturn(PETSC_SUCCESS); 4368 } 4369 4370 /*@ 4371 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4372 4373 Not Collective 4374 4375 Input Parameter: 4376 . dm - The `DMPLEX` 4377 4378 Level: beginner 4379 4380 Note: 4381 This should be called after all calls to `DMPlexSetCone()` 4382 4383 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4384 @*/ 4385 PetscErrorCode DMPlexSymmetrize(DM dm) 4386 { 4387 DM_Plex *mesh = (DM_Plex *)dm->data; 4388 PetscInt *offsets; 4389 PetscInt supportSize; 4390 PetscInt pStart, pEnd, p; 4391 4392 PetscFunctionBegin; 4393 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4394 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4395 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4396 /* Calculate support sizes */ 4397 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4398 for (p = pStart; p < pEnd; ++p) { 4399 PetscInt dof, off, c; 4400 4401 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4402 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4403 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4404 } 4405 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4406 /* Calculate supports */ 4407 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4408 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4409 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4410 for (p = pStart; p < pEnd; ++p) { 4411 PetscInt dof, off, c; 4412 4413 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4414 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4415 for (c = off; c < off + dof; ++c) { 4416 const PetscInt q = mesh->cones[c]; 4417 PetscInt offS; 4418 4419 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4420 4421 mesh->supports[offS + offsets[q]] = p; 4422 ++offsets[q]; 4423 } 4424 } 4425 PetscCall(PetscFree(offsets)); 4426 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4427 PetscFunctionReturn(PETSC_SUCCESS); 4428 } 4429 4430 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4431 { 4432 IS stratumIS; 4433 4434 PetscFunctionBegin; 4435 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4436 if (PetscDefined(USE_DEBUG)) { 4437 PetscInt qStart, qEnd, numLevels, level; 4438 PetscBool overlap = PETSC_FALSE; 4439 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4440 for (level = 0; level < numLevels; level++) { 4441 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4442 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4443 overlap = PETSC_TRUE; 4444 break; 4445 } 4446 } 4447 PetscCheck(!overlap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd); 4448 } 4449 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4450 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4451 PetscCall(ISDestroy(&stratumIS)); 4452 PetscFunctionReturn(PETSC_SUCCESS); 4453 } 4454 4455 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4456 { 4457 PetscInt *pMin, *pMax; 4458 PetscInt pStart, pEnd; 4459 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4460 4461 PetscFunctionBegin; 4462 { 4463 DMLabel label2; 4464 4465 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4466 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4467 } 4468 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4469 for (PetscInt p = pStart; p < pEnd; ++p) { 4470 DMPolytopeType ct; 4471 4472 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4473 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4474 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4475 } 4476 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4477 for (PetscInt d = dmin; d <= dmax; ++d) { 4478 pMin[d] = PETSC_INT_MAX; 4479 pMax[d] = PETSC_INT_MIN; 4480 } 4481 for (PetscInt p = pStart; p < pEnd; ++p) { 4482 DMPolytopeType ct; 4483 PetscInt d; 4484 4485 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4486 d = DMPolytopeTypeGetDim(ct); 4487 pMin[d] = PetscMin(p, pMin[d]); 4488 pMax[d] = PetscMax(p, pMax[d]); 4489 } 4490 for (PetscInt d = dmin; d <= dmax; ++d) { 4491 if (pMin[d] > pMax[d]) continue; 4492 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4493 } 4494 PetscCall(PetscFree2(pMin, pMax)); 4495 PetscFunctionReturn(PETSC_SUCCESS); 4496 } 4497 4498 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4499 { 4500 PetscInt pStart, pEnd; 4501 PetscInt numRoots = 0, numLeaves = 0; 4502 4503 PetscFunctionBegin; 4504 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4505 { 4506 /* Initialize roots and count leaves */ 4507 PetscInt sMin = PETSC_INT_MAX; 4508 PetscInt sMax = PETSC_INT_MIN; 4509 PetscInt coneSize, supportSize; 4510 4511 for (PetscInt p = pStart; p < pEnd; ++p) { 4512 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4513 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4514 if (!coneSize && supportSize) { 4515 sMin = PetscMin(p, sMin); 4516 sMax = PetscMax(p, sMax); 4517 ++numRoots; 4518 } else if (!supportSize && coneSize) { 4519 ++numLeaves; 4520 } else if (!supportSize && !coneSize) { 4521 /* Isolated points */ 4522 sMin = PetscMin(p, sMin); 4523 sMax = PetscMax(p, sMax); 4524 } 4525 } 4526 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4527 } 4528 4529 if (numRoots + numLeaves == (pEnd - pStart)) { 4530 PetscInt sMin = PETSC_INT_MAX; 4531 PetscInt sMax = PETSC_INT_MIN; 4532 PetscInt coneSize, supportSize; 4533 4534 for (PetscInt p = pStart; p < pEnd; ++p) { 4535 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4536 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4537 if (!supportSize && coneSize) { 4538 sMin = PetscMin(p, sMin); 4539 sMax = PetscMax(p, sMax); 4540 } 4541 } 4542 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4543 } else { 4544 PetscInt level = 0; 4545 PetscInt qStart, qEnd; 4546 4547 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4548 while (qEnd > qStart) { 4549 PetscInt sMin = PETSC_INT_MAX; 4550 PetscInt sMax = PETSC_INT_MIN; 4551 4552 for (PetscInt q = qStart; q < qEnd; ++q) { 4553 const PetscInt *support; 4554 PetscInt supportSize; 4555 4556 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4557 PetscCall(DMPlexGetSupport(dm, q, &support)); 4558 for (PetscInt s = 0; s < supportSize; ++s) { 4559 sMin = PetscMin(support[s], sMin); 4560 sMax = PetscMax(support[s], sMax); 4561 } 4562 } 4563 PetscCall(DMLabelGetNumValues(label, &level)); 4564 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4565 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4566 } 4567 } 4568 PetscFunctionReturn(PETSC_SUCCESS); 4569 } 4570 4571 /*@ 4572 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4573 4574 Collective 4575 4576 Input Parameter: 4577 . dm - The `DMPLEX` 4578 4579 Level: beginner 4580 4581 Notes: 4582 The strata group all points of the same grade, and this function calculates the strata. This 4583 grade can be seen as the height (or depth) of the point in the DAG. 4584 4585 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4586 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4587 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4588 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4589 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4590 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4591 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4592 4593 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4594 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4595 we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose 4596 to interpolate only that one (e0), so that 4597 .vb 4598 cone(c0) = {e0, v2} 4599 cone(e0) = {v0, v1} 4600 .ve 4601 If `DMPlexStratify()` is run on this mesh, it will give depths 4602 .vb 4603 depth 0 = {v0, v1, v2} 4604 depth 1 = {e0, c0} 4605 .ve 4606 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4607 4608 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4609 4610 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4611 @*/ 4612 PetscErrorCode DMPlexStratify(DM dm) 4613 { 4614 DM_Plex *mesh = (DM_Plex *)dm->data; 4615 DMLabel label; 4616 PetscBool flg = PETSC_FALSE; 4617 4618 PetscFunctionBegin; 4619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4620 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4621 4622 // Create depth label 4623 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4624 PetscCall(DMCreateLabel(dm, "depth")); 4625 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4626 4627 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4628 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4629 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4630 4631 { /* just in case there is an empty process */ 4632 PetscInt numValues, maxValues = 0, v; 4633 4634 PetscCall(DMLabelGetNumValues(label, &numValues)); 4635 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4636 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4637 } 4638 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4639 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4640 PetscFunctionReturn(PETSC_SUCCESS); 4641 } 4642 4643 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4644 { 4645 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4646 PetscInt dim, depth, pheight, coneSize; 4647 PetscBool preferTensor; 4648 4649 PetscFunctionBeginHot; 4650 PetscCall(DMGetDimension(dm, &dim)); 4651 PetscCall(DMPlexGetDepth(dm, &depth)); 4652 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4653 PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor)); 4654 pheight = depth - pdepth; 4655 if (depth <= 1) { 4656 switch (pdepth) { 4657 case 0: 4658 ct = DM_POLYTOPE_POINT; 4659 break; 4660 case 1: 4661 switch (coneSize) { 4662 case 2: 4663 ct = DM_POLYTOPE_SEGMENT; 4664 break; 4665 case 3: 4666 ct = DM_POLYTOPE_TRIANGLE; 4667 break; 4668 case 4: 4669 switch (dim) { 4670 case 2: 4671 ct = DM_POLYTOPE_QUADRILATERAL; 4672 break; 4673 case 3: 4674 ct = DM_POLYTOPE_TETRAHEDRON; 4675 break; 4676 default: 4677 break; 4678 } 4679 break; 4680 case 5: 4681 ct = DM_POLYTOPE_PYRAMID; 4682 break; 4683 case 6: 4684 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4685 break; 4686 case 8: 4687 ct = DM_POLYTOPE_HEXAHEDRON; 4688 break; 4689 default: 4690 break; 4691 } 4692 } 4693 } else { 4694 if (pdepth == 0) { 4695 ct = DM_POLYTOPE_POINT; 4696 } else if (pheight == 0) { 4697 switch (dim) { 4698 case 1: 4699 switch (coneSize) { 4700 case 2: 4701 ct = DM_POLYTOPE_SEGMENT; 4702 break; 4703 default: 4704 break; 4705 } 4706 break; 4707 case 2: 4708 switch (coneSize) { 4709 case 3: 4710 ct = DM_POLYTOPE_TRIANGLE; 4711 break; 4712 case 4: 4713 ct = DM_POLYTOPE_QUADRILATERAL; 4714 break; 4715 default: 4716 break; 4717 } 4718 break; 4719 case 3: 4720 switch (coneSize) { 4721 case 4: 4722 ct = DM_POLYTOPE_TETRAHEDRON; 4723 break; 4724 case 5: { 4725 const PetscInt *cone; 4726 PetscInt faceConeSize; 4727 4728 PetscCall(DMPlexGetCone(dm, p, &cone)); 4729 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4730 switch (faceConeSize) { 4731 case 3: 4732 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4733 break; 4734 case 4: 4735 ct = DM_POLYTOPE_PYRAMID; 4736 break; 4737 } 4738 } break; 4739 case 6: 4740 ct = DM_POLYTOPE_HEXAHEDRON; 4741 break; 4742 default: 4743 break; 4744 } 4745 break; 4746 default: 4747 break; 4748 } 4749 } else if (pheight > 0) { 4750 switch (coneSize) { 4751 case 2: 4752 ct = DM_POLYTOPE_SEGMENT; 4753 break; 4754 case 3: 4755 ct = DM_POLYTOPE_TRIANGLE; 4756 break; 4757 case 4: 4758 ct = DM_POLYTOPE_QUADRILATERAL; 4759 break; 4760 default: 4761 break; 4762 } 4763 } 4764 } 4765 *pt = ct; 4766 PetscFunctionReturn(PETSC_SUCCESS); 4767 } 4768 4769 /*@ 4770 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4771 4772 Collective 4773 4774 Input Parameter: 4775 . dm - The `DMPLEX` 4776 4777 Level: developer 4778 4779 Note: 4780 This function is normally called automatically when a cell type is requested. It creates an 4781 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4782 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4783 4784 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4785 4786 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4787 @*/ 4788 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4789 { 4790 DM_Plex *mesh; 4791 DMLabel ctLabel; 4792 PetscInt pStart, pEnd, p; 4793 4794 PetscFunctionBegin; 4795 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4796 mesh = (DM_Plex *)dm->data; 4797 PetscCall(DMCreateLabel(dm, "celltype")); 4798 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4799 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4800 PetscCall(PetscFree(mesh->cellTypes)); 4801 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4802 for (p = pStart; p < pEnd; ++p) { 4803 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4804 PetscInt pdepth; 4805 4806 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4807 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4808 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]); 4809 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4810 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4811 } 4812 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4813 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4814 PetscFunctionReturn(PETSC_SUCCESS); 4815 } 4816 4817 /*@C 4818 DMPlexGetJoin - Get an array for the join of the set of points 4819 4820 Not Collective 4821 4822 Input Parameters: 4823 + dm - The `DMPLEX` object 4824 . numPoints - The number of input points for the join 4825 - points - The input points 4826 4827 Output Parameters: 4828 + numCoveredPoints - The number of points in the join 4829 - coveredPoints - The points in the join 4830 4831 Level: intermediate 4832 4833 Note: 4834 Currently, this is restricted to a single level join 4835 4836 Fortran Notes: 4837 `converedPoints` must be declared with 4838 .vb 4839 PetscInt, pointer :: coveredPints(:) 4840 .ve 4841 4842 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4843 @*/ 4844 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4845 { 4846 DM_Plex *mesh = (DM_Plex *)dm->data; 4847 PetscInt *join[2]; 4848 PetscInt joinSize, i = 0; 4849 PetscInt dof, off, p, c, m; 4850 PetscInt maxSupportSize; 4851 4852 PetscFunctionBegin; 4853 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4854 PetscAssertPointer(points, 3); 4855 PetscAssertPointer(numCoveredPoints, 4); 4856 PetscAssertPointer(coveredPoints, 5); 4857 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4858 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4859 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4860 /* Copy in support of first point */ 4861 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4862 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4863 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4864 /* Check each successive support */ 4865 for (p = 1; p < numPoints; ++p) { 4866 PetscInt newJoinSize = 0; 4867 4868 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4869 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4870 for (c = 0; c < dof; ++c) { 4871 const PetscInt point = mesh->supports[off + c]; 4872 4873 for (m = 0; m < joinSize; ++m) { 4874 if (point == join[i][m]) { 4875 join[1 - i][newJoinSize++] = point; 4876 break; 4877 } 4878 } 4879 } 4880 joinSize = newJoinSize; 4881 i = 1 - i; 4882 } 4883 *numCoveredPoints = joinSize; 4884 *coveredPoints = join[i]; 4885 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4886 PetscFunctionReturn(PETSC_SUCCESS); 4887 } 4888 4889 /*@C 4890 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4891 4892 Not Collective 4893 4894 Input Parameters: 4895 + dm - The `DMPLEX` object 4896 . numPoints - The number of input points for the join 4897 - points - The input points 4898 4899 Output Parameters: 4900 + numCoveredPoints - The number of points in the join 4901 - coveredPoints - The points in the join 4902 4903 Level: intermediate 4904 4905 Fortran Notes: 4906 `converedPoints` must be declared with 4907 .vb 4908 PetscInt, pointer :: coveredPoints(:) 4909 .ve 4910 4911 Pass `PETSC_NULL_INTEGER` for `numCoveredPoints` if it is not needed 4912 4913 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4914 @*/ 4915 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4916 { 4917 PetscFunctionBegin; 4918 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4919 if (points) PetscAssertPointer(points, 3); 4920 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4921 PetscAssertPointer(coveredPoints, 5); 4922 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4923 if (numCoveredPoints) *numCoveredPoints = 0; 4924 PetscFunctionReturn(PETSC_SUCCESS); 4925 } 4926 4927 /*@C 4928 DMPlexGetFullJoin - Get an array for the join of the set of points 4929 4930 Not Collective 4931 4932 Input Parameters: 4933 + dm - The `DMPLEX` object 4934 . numPoints - The number of input points for the join 4935 - points - The input points, its length is `numPoints` 4936 4937 Output Parameters: 4938 + numCoveredPoints - The number of points in the join 4939 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4940 4941 Level: intermediate 4942 4943 Fortran Notes: 4944 .vb 4945 PetscInt, pointer :: coveredPints(:) 4946 .ve 4947 4948 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4949 @*/ 4950 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4951 { 4952 PetscInt *offsets, **closures; 4953 PetscInt *join[2]; 4954 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4955 PetscInt p, d, c, m, ms; 4956 4957 PetscFunctionBegin; 4958 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4959 PetscAssertPointer(points, 3); 4960 PetscAssertPointer(numCoveredPoints, 4); 4961 PetscAssertPointer(coveredPoints, 5); 4962 4963 PetscCall(DMPlexGetDepth(dm, &depth)); 4964 PetscCall(PetscCalloc1(numPoints, &closures)); 4965 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4966 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4967 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4968 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4969 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4970 4971 for (p = 0; p < numPoints; ++p) { 4972 PetscInt closureSize; 4973 4974 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4975 4976 offsets[p * (depth + 2) + 0] = 0; 4977 for (d = 0; d < depth + 1; ++d) { 4978 PetscInt pStart, pEnd, i; 4979 4980 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4981 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4982 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4983 offsets[p * (depth + 2) + d + 1] = i; 4984 break; 4985 } 4986 } 4987 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4988 } 4989 PetscCheck(offsets[p * (depth + 2) + depth + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (depth + 2) + depth + 1], closureSize); 4990 } 4991 for (d = 0; d < depth + 1; ++d) { 4992 PetscInt dof; 4993 4994 /* Copy in support of first point */ 4995 dof = offsets[d + 1] - offsets[d]; 4996 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4997 /* Check each successive cone */ 4998 for (p = 1; p < numPoints && joinSize; ++p) { 4999 PetscInt newJoinSize = 0; 5000 5001 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 5002 for (c = 0; c < dof; ++c) { 5003 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 5004 5005 for (m = 0; m < joinSize; ++m) { 5006 if (point == join[i][m]) { 5007 join[1 - i][newJoinSize++] = point; 5008 break; 5009 } 5010 } 5011 } 5012 joinSize = newJoinSize; 5013 i = 1 - i; 5014 } 5015 if (joinSize) break; 5016 } 5017 *numCoveredPoints = joinSize; 5018 *coveredPoints = join[i]; 5019 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 5020 PetscCall(PetscFree(closures)); 5021 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 5022 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 5023 PetscFunctionReturn(PETSC_SUCCESS); 5024 } 5025 5026 /*@C 5027 DMPlexGetMeet - Get an array for the meet of the set of points 5028 5029 Not Collective 5030 5031 Input Parameters: 5032 + dm - The `DMPLEX` object 5033 . numPoints - The number of input points for the meet 5034 - points - The input points, of length `numPoints` 5035 5036 Output Parameters: 5037 + numCoveringPoints - The number of points in the meet 5038 - coveringPoints - The points in the meet, of length `numCoveringPoints` 5039 5040 Level: intermediate 5041 5042 Note: 5043 Currently, this is restricted to a single level meet 5044 5045 Fortran Note: 5046 `coveringPoints` must be declared with 5047 .vb 5048 PetscInt, pointer :: coveringPoints(:) 5049 .ve 5050 5051 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5052 @*/ 5053 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 5054 { 5055 DM_Plex *mesh = (DM_Plex *)dm->data; 5056 PetscInt *meet[2]; 5057 PetscInt meetSize, i = 0; 5058 PetscInt dof, off, p, c, m; 5059 PetscInt maxConeSize; 5060 5061 PetscFunctionBegin; 5062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5063 PetscAssertPointer(points, 3); 5064 PetscAssertPointer(numCoveringPoints, 4); 5065 PetscAssertPointer(coveringPoints, 5); 5066 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 5067 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 5068 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 5069 /* Copy in cone of first point */ 5070 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 5071 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 5072 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5073 /* Check each successive cone */ 5074 for (p = 1; p < numPoints; ++p) { 5075 PetscInt newMeetSize = 0; 5076 5077 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5078 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5079 for (c = 0; c < dof; ++c) { 5080 const PetscInt point = mesh->cones[off + c]; 5081 5082 for (m = 0; m < meetSize; ++m) { 5083 if (point == meet[i][m]) { 5084 meet[1 - i][newMeetSize++] = point; 5085 break; 5086 } 5087 } 5088 } 5089 meetSize = newMeetSize; 5090 i = 1 - i; 5091 } 5092 *numCoveringPoints = meetSize; 5093 *coveringPoints = meet[i]; 5094 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5095 PetscFunctionReturn(PETSC_SUCCESS); 5096 } 5097 5098 /*@C 5099 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5100 5101 Not Collective 5102 5103 Input Parameters: 5104 + dm - The `DMPLEX` object 5105 . numPoints - The number of input points for the meet 5106 - points - The input points 5107 5108 Output Parameters: 5109 + numCoveredPoints - The number of points in the meet 5110 - coveredPoints - The points in the meet 5111 5112 Level: intermediate 5113 5114 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5115 @*/ 5116 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5117 { 5118 PetscFunctionBegin; 5119 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5120 if (points) PetscAssertPointer(points, 3); 5121 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5122 PetscAssertPointer(coveredPoints, 5); 5123 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5124 if (numCoveredPoints) *numCoveredPoints = 0; 5125 PetscFunctionReturn(PETSC_SUCCESS); 5126 } 5127 5128 /*@C 5129 DMPlexGetFullMeet - Get an array for the meet of the set of points 5130 5131 Not Collective 5132 5133 Input Parameters: 5134 + dm - The `DMPLEX` object 5135 . numPoints - The number of input points for the meet 5136 - points - The input points, of length `numPoints` 5137 5138 Output Parameters: 5139 + numCoveredPoints - The number of points in the meet 5140 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5141 5142 Level: intermediate 5143 5144 Fortran Notes: 5145 `coveredPoints` must be declared with 5146 .vb 5147 PetscInt, pointer :: coveredPoints(:) 5148 .ve 5149 5150 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5151 @*/ 5152 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5153 { 5154 PetscInt *offsets, **closures; 5155 PetscInt *meet[2]; 5156 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5157 PetscInt p, h, c, m, mc; 5158 5159 PetscFunctionBegin; 5160 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5161 PetscAssertPointer(points, 3); 5162 PetscAssertPointer(numCoveredPoints, 4); 5163 PetscAssertPointer(coveredPoints, 5); 5164 5165 PetscCall(DMPlexGetDepth(dm, &height)); 5166 PetscCall(PetscMalloc1(numPoints, &closures)); 5167 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5168 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5169 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5170 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5171 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5172 5173 for (p = 0; p < numPoints; ++p) { 5174 PetscInt closureSize; 5175 5176 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5177 5178 offsets[p * (height + 2) + 0] = 0; 5179 for (h = 0; h < height + 1; ++h) { 5180 PetscInt pStart, pEnd, i; 5181 5182 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5183 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5184 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5185 offsets[p * (height + 2) + h + 1] = i; 5186 break; 5187 } 5188 } 5189 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5190 } 5191 PetscCheck(offsets[p * (height + 2) + height + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (height + 2) + height + 1], closureSize); 5192 } 5193 for (h = 0; h < height + 1; ++h) { 5194 PetscInt dof; 5195 5196 /* Copy in cone of first point */ 5197 dof = offsets[h + 1] - offsets[h]; 5198 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5199 /* Check each successive cone */ 5200 for (p = 1; p < numPoints && meetSize; ++p) { 5201 PetscInt newMeetSize = 0; 5202 5203 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5204 for (c = 0; c < dof; ++c) { 5205 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5206 5207 for (m = 0; m < meetSize; ++m) { 5208 if (point == meet[i][m]) { 5209 meet[1 - i][newMeetSize++] = point; 5210 break; 5211 } 5212 } 5213 } 5214 meetSize = newMeetSize; 5215 i = 1 - i; 5216 } 5217 if (meetSize) break; 5218 } 5219 *numCoveredPoints = meetSize; 5220 *coveredPoints = meet[i]; 5221 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5222 PetscCall(PetscFree(closures)); 5223 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5224 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5225 PetscFunctionReturn(PETSC_SUCCESS); 5226 } 5227 5228 /*@ 5229 DMPlexEqual - Determine if two `DM` have the same topology 5230 5231 Not Collective 5232 5233 Input Parameters: 5234 + dmA - A `DMPLEX` object 5235 - dmB - A `DMPLEX` object 5236 5237 Output Parameter: 5238 . equal - `PETSC_TRUE` if the topologies are identical 5239 5240 Level: intermediate 5241 5242 Note: 5243 We are not solving graph isomorphism, so we do not permute. 5244 5245 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5246 @*/ 5247 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5248 { 5249 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5250 5251 PetscFunctionBegin; 5252 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5253 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5254 PetscAssertPointer(equal, 3); 5255 5256 *equal = PETSC_FALSE; 5257 PetscCall(DMPlexGetDepth(dmA, &depth)); 5258 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5259 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5260 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5261 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5262 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5263 for (p = pStart; p < pEnd; ++p) { 5264 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5265 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5266 5267 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5268 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5269 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5270 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5271 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5272 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5273 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5274 for (c = 0; c < coneSize; ++c) { 5275 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5276 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5277 } 5278 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5279 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5280 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5281 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5282 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5283 for (s = 0; s < supportSize; ++s) { 5284 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5285 } 5286 } 5287 *equal = PETSC_TRUE; 5288 PetscFunctionReturn(PETSC_SUCCESS); 5289 } 5290 5291 /*@ 5292 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5293 5294 Not Collective 5295 5296 Input Parameters: 5297 + dm - The `DMPLEX` 5298 . cellDim - The cell dimension 5299 - numCorners - The number of vertices on a cell 5300 5301 Output Parameter: 5302 . numFaceVertices - The number of vertices on a face 5303 5304 Level: developer 5305 5306 Note: 5307 Of course this can only work for a restricted set of symmetric shapes 5308 5309 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5310 @*/ 5311 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5312 { 5313 MPI_Comm comm; 5314 5315 PetscFunctionBegin; 5316 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5317 PetscAssertPointer(numFaceVertices, 4); 5318 switch (cellDim) { 5319 case 0: 5320 *numFaceVertices = 0; 5321 break; 5322 case 1: 5323 *numFaceVertices = 1; 5324 break; 5325 case 2: 5326 switch (numCorners) { 5327 case 3: /* triangle */ 5328 *numFaceVertices = 2; /* Edge has 2 vertices */ 5329 break; 5330 case 4: /* quadrilateral */ 5331 *numFaceVertices = 2; /* Edge has 2 vertices */ 5332 break; 5333 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5334 *numFaceVertices = 3; /* Edge has 3 vertices */ 5335 break; 5336 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5337 *numFaceVertices = 3; /* Edge has 3 vertices */ 5338 break; 5339 default: 5340 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5341 } 5342 break; 5343 case 3: 5344 switch (numCorners) { 5345 case 4: /* tetradehdron */ 5346 *numFaceVertices = 3; /* Face has 3 vertices */ 5347 break; 5348 case 6: /* tet cohesive cells */ 5349 *numFaceVertices = 4; /* Face has 4 vertices */ 5350 break; 5351 case 8: /* hexahedron */ 5352 *numFaceVertices = 4; /* Face has 4 vertices */ 5353 break; 5354 case 9: /* tet cohesive Lagrange cells */ 5355 *numFaceVertices = 6; /* Face has 6 vertices */ 5356 break; 5357 case 10: /* quadratic tetrahedron */ 5358 *numFaceVertices = 6; /* Face has 6 vertices */ 5359 break; 5360 case 12: /* hex cohesive Lagrange cells */ 5361 *numFaceVertices = 6; /* Face has 6 vertices */ 5362 break; 5363 case 18: /* quadratic tet cohesive Lagrange cells */ 5364 *numFaceVertices = 6; /* Face has 6 vertices */ 5365 break; 5366 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5367 *numFaceVertices = 9; /* Face has 9 vertices */ 5368 break; 5369 default: 5370 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5371 } 5372 break; 5373 default: 5374 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5375 } 5376 PetscFunctionReturn(PETSC_SUCCESS); 5377 } 5378 5379 /*@ 5380 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5381 5382 Not Collective 5383 5384 Input Parameter: 5385 . dm - The `DMPLEX` object 5386 5387 Output Parameter: 5388 . depthLabel - The `DMLabel` recording point depth 5389 5390 Level: developer 5391 5392 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5393 @*/ 5394 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5395 { 5396 PetscFunctionBegin; 5397 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5398 PetscAssertPointer(depthLabel, 2); 5399 *depthLabel = dm->depthLabel; 5400 PetscFunctionReturn(PETSC_SUCCESS); 5401 } 5402 5403 /*@ 5404 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5405 5406 Not Collective 5407 5408 Input Parameter: 5409 . dm - The `DMPLEX` object 5410 5411 Output Parameter: 5412 . depth - The number of strata (breadth first levels) in the DAG 5413 5414 Level: developer 5415 5416 Notes: 5417 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5418 5419 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5420 5421 An empty mesh gives -1. 5422 5423 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5424 @*/ 5425 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5426 { 5427 DM_Plex *mesh = (DM_Plex *)dm->data; 5428 DMLabel label; 5429 PetscInt d = -1; 5430 5431 PetscFunctionBegin; 5432 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5433 PetscAssertPointer(depth, 2); 5434 if (mesh->tr) { 5435 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5436 } else { 5437 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5438 // Allow missing depths 5439 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5440 *depth = d; 5441 } 5442 PetscFunctionReturn(PETSC_SUCCESS); 5443 } 5444 5445 /*@ 5446 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5447 5448 Not Collective 5449 5450 Input Parameters: 5451 + dm - The `DMPLEX` object 5452 - depth - The requested depth 5453 5454 Output Parameters: 5455 + start - The first point at this `depth` 5456 - end - One beyond the last point at this `depth` 5457 5458 Level: developer 5459 5460 Notes: 5461 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5462 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5463 higher dimension, e.g., "edges". 5464 5465 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5466 @*/ 5467 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PeOp PetscInt *start, PeOp PetscInt *end) 5468 { 5469 DM_Plex *mesh = (DM_Plex *)dm->data; 5470 DMLabel label; 5471 PetscInt pStart, pEnd; 5472 5473 PetscFunctionBegin; 5474 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5475 if (start) { 5476 PetscAssertPointer(start, 3); 5477 *start = 0; 5478 } 5479 if (end) { 5480 PetscAssertPointer(end, 4); 5481 *end = 0; 5482 } 5483 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5484 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5485 if (depth < 0) { 5486 if (start) *start = pStart; 5487 if (end) *end = pEnd; 5488 PetscFunctionReturn(PETSC_SUCCESS); 5489 } 5490 if (mesh->tr) { 5491 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5492 } else { 5493 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5494 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5495 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5496 } 5497 PetscFunctionReturn(PETSC_SUCCESS); 5498 } 5499 5500 /*@ 5501 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5502 5503 Not Collective 5504 5505 Input Parameters: 5506 + dm - The `DMPLEX` object 5507 - height - The requested height 5508 5509 Output Parameters: 5510 + start - The first point at this `height` 5511 - end - One beyond the last point at this `height` 5512 5513 Level: developer 5514 5515 Notes: 5516 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5517 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5518 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5519 5520 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5521 @*/ 5522 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PeOp PetscInt *start, PeOp PetscInt *end) 5523 { 5524 DMLabel label; 5525 PetscInt depth, pStart, pEnd; 5526 5527 PetscFunctionBegin; 5528 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5529 if (start) { 5530 PetscAssertPointer(start, 3); 5531 *start = 0; 5532 } 5533 if (end) { 5534 PetscAssertPointer(end, 4); 5535 *end = 0; 5536 } 5537 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5538 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5539 if (height < 0) { 5540 if (start) *start = pStart; 5541 if (end) *end = pEnd; 5542 PetscFunctionReturn(PETSC_SUCCESS); 5543 } 5544 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5545 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5546 else PetscCall(DMGetDimension(dm, &depth)); 5547 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5548 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5549 PetscFunctionReturn(PETSC_SUCCESS); 5550 } 5551 5552 /*@ 5553 DMPlexGetPointDepth - Get the `depth` of a given point 5554 5555 Not Collective 5556 5557 Input Parameters: 5558 + dm - The `DMPLEX` object 5559 - point - The point 5560 5561 Output Parameter: 5562 . depth - The depth of the `point` 5563 5564 Level: intermediate 5565 5566 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5567 @*/ 5568 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5569 { 5570 PetscFunctionBegin; 5571 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5572 PetscAssertPointer(depth, 3); 5573 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5574 PetscFunctionReturn(PETSC_SUCCESS); 5575 } 5576 5577 /*@ 5578 DMPlexGetPointHeight - Get the `height` of a given point 5579 5580 Not Collective 5581 5582 Input Parameters: 5583 + dm - The `DMPLEX` object 5584 - point - The point 5585 5586 Output Parameter: 5587 . height - The height of the `point` 5588 5589 Level: intermediate 5590 5591 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5592 @*/ 5593 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5594 { 5595 PetscInt n, pDepth; 5596 5597 PetscFunctionBegin; 5598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5599 PetscAssertPointer(height, 3); 5600 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5601 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5602 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5603 PetscFunctionReturn(PETSC_SUCCESS); 5604 } 5605 5606 /*@ 5607 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5608 5609 Not Collective 5610 5611 Input Parameter: 5612 . dm - The `DMPLEX` object 5613 5614 Output Parameter: 5615 . celltypeLabel - The `DMLabel` recording cell polytope type 5616 5617 Level: developer 5618 5619 Note: 5620 This function will trigger automatica computation of cell types. This can be disabled by calling 5621 `DMCreateLabel`(dm, "celltype") beforehand. 5622 5623 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5624 @*/ 5625 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5626 { 5627 PetscFunctionBegin; 5628 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5629 PetscAssertPointer(celltypeLabel, 2); 5630 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5631 *celltypeLabel = dm->celltypeLabel; 5632 PetscFunctionReturn(PETSC_SUCCESS); 5633 } 5634 5635 /*@ 5636 DMPlexGetCellType - Get the polytope type of a given cell 5637 5638 Not Collective 5639 5640 Input Parameters: 5641 + dm - The `DMPLEX` object 5642 - cell - The cell 5643 5644 Output Parameter: 5645 . celltype - The polytope type of the cell 5646 5647 Level: intermediate 5648 5649 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5650 @*/ 5651 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5652 { 5653 DM_Plex *mesh = (DM_Plex *)dm->data; 5654 DMLabel label; 5655 PetscInt ct; 5656 5657 PetscFunctionBegin; 5658 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5659 PetscAssertPointer(celltype, 3); 5660 if (mesh->tr) { 5661 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5662 } else { 5663 PetscInt pStart, pEnd; 5664 5665 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5666 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5667 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5668 if (pEnd <= pStart) { 5669 *celltype = DM_POLYTOPE_UNKNOWN; 5670 PetscFunctionReturn(PETSC_SUCCESS); 5671 } 5672 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5673 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5674 for (PetscInt p = pStart; p < pEnd; p++) { 5675 PetscCall(DMLabelGetValue(label, p, &ct)); 5676 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5677 } 5678 } 5679 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5680 if (PetscDefined(USE_DEBUG)) { 5681 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5682 PetscCall(DMLabelGetValue(label, cell, &ct)); 5683 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5684 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5685 } 5686 } 5687 PetscFunctionReturn(PETSC_SUCCESS); 5688 } 5689 5690 /*@ 5691 DMPlexSetCellType - Set the polytope type of a given cell 5692 5693 Not Collective 5694 5695 Input Parameters: 5696 + dm - The `DMPLEX` object 5697 . cell - The cell 5698 - celltype - The polytope type of the cell 5699 5700 Level: advanced 5701 5702 Note: 5703 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5704 is executed. This function will override the computed type. However, if automatic classification will not succeed 5705 and a user wants to manually specify all types, the classification must be disabled by calling 5706 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5707 5708 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5709 @*/ 5710 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5711 { 5712 DM_Plex *mesh = (DM_Plex *)dm->data; 5713 DMLabel label; 5714 PetscInt pStart, pEnd; 5715 5716 PetscFunctionBegin; 5717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5718 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5719 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5720 PetscCall(DMLabelSetValue(label, cell, celltype)); 5721 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5722 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5723 PetscFunctionReturn(PETSC_SUCCESS); 5724 } 5725 5726 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5727 { 5728 PetscSection section; 5729 PetscInt maxHeight; 5730 const char *prefix; 5731 5732 PetscFunctionBegin; 5733 PetscCall(DMClone(dm, cdm)); 5734 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5735 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5736 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5737 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5738 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5739 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5740 PetscCall(DMSetLocalSection(*cdm, section)); 5741 PetscCall(PetscSectionDestroy(§ion)); 5742 5743 PetscCall(DMSetNumFields(*cdm, 1)); 5744 PetscCall(DMCreateDS(*cdm)); 5745 (*cdm)->cloneOpts = PETSC_TRUE; 5746 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5747 PetscFunctionReturn(PETSC_SUCCESS); 5748 } 5749 5750 PetscErrorCode DMCreateCellCoordinateDM_Plex(DM dm, DM *cdm) 5751 { 5752 DM cgcdm; 5753 PetscSection section; 5754 const char *prefix; 5755 5756 PetscFunctionBegin; 5757 PetscCall(DMGetCoordinateDM(dm, &cgcdm)); 5758 PetscCall(DMClone(cgcdm, cdm)); 5759 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5760 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5761 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cellcdm_")); 5762 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5763 PetscCall(DMSetLocalSection(*cdm, section)); 5764 PetscCall(PetscSectionDestroy(§ion)); 5765 PetscCall(DMSetNumFields(*cdm, 1)); 5766 PetscCall(DMCreateDS(*cdm)); 5767 (*cdm)->cloneOpts = PETSC_TRUE; 5768 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5769 PetscFunctionReturn(PETSC_SUCCESS); 5770 } 5771 5772 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5773 { 5774 Vec coordsLocal, cellCoordsLocal; 5775 DM coordsDM, cellCoordsDM; 5776 5777 PetscFunctionBegin; 5778 *field = NULL; 5779 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5780 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5781 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5782 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5783 if (coordsLocal && coordsDM) { 5784 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5785 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5786 } 5787 PetscFunctionReturn(PETSC_SUCCESS); 5788 } 5789 5790 /*@ 5791 DMPlexGetConeSection - Return a section which describes the layout of cone data 5792 5793 Not Collective 5794 5795 Input Parameter: 5796 . dm - The `DMPLEX` object 5797 5798 Output Parameter: 5799 . section - The `PetscSection` object 5800 5801 Level: developer 5802 5803 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5804 @*/ 5805 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5806 { 5807 DM_Plex *mesh = (DM_Plex *)dm->data; 5808 5809 PetscFunctionBegin; 5810 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5811 if (section) *section = mesh->coneSection; 5812 PetscFunctionReturn(PETSC_SUCCESS); 5813 } 5814 5815 /*@ 5816 DMPlexGetSupportSection - Return a section which describes the layout of support data 5817 5818 Not Collective 5819 5820 Input Parameter: 5821 . dm - The `DMPLEX` object 5822 5823 Output Parameter: 5824 . section - The `PetscSection` object 5825 5826 Level: developer 5827 5828 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5829 @*/ 5830 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5831 { 5832 DM_Plex *mesh = (DM_Plex *)dm->data; 5833 5834 PetscFunctionBegin; 5835 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5836 if (section) *section = mesh->supportSection; 5837 PetscFunctionReturn(PETSC_SUCCESS); 5838 } 5839 5840 /*@C 5841 DMPlexGetCones - Return cone data 5842 5843 Not Collective 5844 5845 Input Parameter: 5846 . dm - The `DMPLEX` object 5847 5848 Output Parameter: 5849 . cones - The cone for each point 5850 5851 Level: developer 5852 5853 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5854 @*/ 5855 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5856 { 5857 DM_Plex *mesh = (DM_Plex *)dm->data; 5858 5859 PetscFunctionBegin; 5860 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5861 if (cones) *cones = mesh->cones; 5862 PetscFunctionReturn(PETSC_SUCCESS); 5863 } 5864 5865 /*@C 5866 DMPlexGetConeOrientations - Return cone orientation data 5867 5868 Not Collective 5869 5870 Input Parameter: 5871 . dm - The `DMPLEX` object 5872 5873 Output Parameter: 5874 . coneOrientations - The array of cone orientations for all points 5875 5876 Level: developer 5877 5878 Notes: 5879 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5880 as returned by `DMPlexGetConeOrientation()`. 5881 5882 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5883 5884 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5885 @*/ 5886 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5887 { 5888 DM_Plex *mesh = (DM_Plex *)dm->data; 5889 5890 PetscFunctionBegin; 5891 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5892 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5893 PetscFunctionReturn(PETSC_SUCCESS); 5894 } 5895 5896 /* FEM Support */ 5897 5898 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5899 { 5900 PetscInt depth; 5901 5902 PetscFunctionBegin; 5903 PetscCall(DMPlexGetDepth(plex, &depth)); 5904 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5905 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5906 PetscFunctionReturn(PETSC_SUCCESS); 5907 } 5908 5909 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5910 { 5911 PetscInt depth; 5912 5913 PetscFunctionBegin; 5914 PetscCall(DMPlexGetDepth(plex, &depth)); 5915 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5916 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5917 PetscFunctionReturn(PETSC_SUCCESS); 5918 } 5919 5920 /* 5921 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5922 representing a line in the section. 5923 */ 5924 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5925 { 5926 PetscObject obj; 5927 PetscClassId id; 5928 PetscFE fe = NULL; 5929 5930 PetscFunctionBeginHot; 5931 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5932 PetscCall(DMGetField(dm, field, NULL, &obj)); 5933 PetscCall(PetscObjectGetClassId(obj, &id)); 5934 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5935 5936 if (!fe) { 5937 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5938 /* An order k SEM disc has k-1 dofs on an edge */ 5939 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5940 *k = *k / *Nc + 1; 5941 } else { 5942 PetscInt dual_space_size, dim; 5943 PetscDualSpace dsp; 5944 5945 PetscCall(DMGetDimension(dm, &dim)); 5946 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5947 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5948 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5949 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5950 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5951 } 5952 PetscFunctionReturn(PETSC_SUCCESS); 5953 } 5954 5955 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5956 { 5957 PetscFunctionBeginHot; 5958 if (tensor) { 5959 *dof = PetscPowInt(k + 1, dim); 5960 } else { 5961 switch (dim) { 5962 case 1: 5963 *dof = k + 1; 5964 break; 5965 case 2: 5966 *dof = ((k + 1) * (k + 2)) / 2; 5967 break; 5968 case 3: 5969 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5970 break; 5971 default: 5972 *dof = 0; 5973 } 5974 } 5975 PetscFunctionReturn(PETSC_SUCCESS); 5976 } 5977 5978 /*@ 5979 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5980 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5981 section provided (or the section of the `DM`). 5982 5983 Input Parameters: 5984 + dm - The `DM` 5985 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5986 - section - The `PetscSection` to reorder, or `NULL` for the default section 5987 5988 Example: 5989 A typical interpolated single-quad mesh might order points as 5990 .vb 5991 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5992 5993 v4 -- e6 -- v3 5994 | | 5995 e7 c0 e8 5996 | | 5997 v1 -- e5 -- v2 5998 .ve 5999 6000 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 6001 dofs in the order of points, e.g., 6002 .vb 6003 c0 -> [0,1,2,3] 6004 v1 -> [4] 6005 ... 6006 e5 -> [8, 9] 6007 .ve 6008 6009 which corresponds to the dofs 6010 .vb 6011 6 10 11 7 6012 13 2 3 15 6013 12 0 1 14 6014 4 8 9 5 6015 .ve 6016 6017 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 6018 .vb 6019 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 6020 .ve 6021 6022 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 6023 .vb 6024 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 6025 .ve 6026 6027 Level: developer 6028 6029 Notes: 6030 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 6031 degree of the basis. 6032 6033 This is required to run with libCEED. 6034 6035 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 6036 @*/ 6037 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 6038 { 6039 DMLabel label; 6040 PetscInt dim, depth = -1, eStart = -1, Nf; 6041 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 6042 6043 PetscFunctionBegin; 6044 PetscCall(DMGetDimension(dm, &dim)); 6045 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 6046 if (point < 0) { 6047 PetscInt sStart, sEnd; 6048 6049 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6050 point = sEnd - sStart ? sStart : point; 6051 } 6052 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6053 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6054 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6055 if (depth == 1) { 6056 eStart = point; 6057 } else if (depth == dim) { 6058 const PetscInt *cone; 6059 6060 PetscCall(DMPlexGetCone(dm, point, &cone)); 6061 if (dim == 2) eStart = cone[0]; 6062 else if (dim == 3) { 6063 const PetscInt *cone2; 6064 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6065 eStart = cone2[0]; 6066 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 6067 } else PetscCheck(depth < 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 6068 6069 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6070 for (PetscInt d = 1; d <= dim; d++) { 6071 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6072 PetscInt *perm; 6073 6074 for (f = 0; f < Nf; ++f) { 6075 PetscInt dof; 6076 6077 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6078 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6079 if (!continuous && d < dim) continue; 6080 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6081 size += dof * Nc; 6082 } 6083 PetscCall(PetscMalloc1(size, &perm)); 6084 for (f = 0; f < Nf; ++f) { 6085 switch (d) { 6086 case 1: 6087 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6088 if (!continuous && d < dim) continue; 6089 /* 6090 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6091 We want [ vtx0; edge of length k-1; vtx1 ] 6092 */ 6093 if (continuous) { 6094 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6095 for (i = 0; i < k - 1; i++) 6096 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6097 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6098 foffset = offset; 6099 } else { 6100 PetscInt dof; 6101 6102 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6103 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6104 foffset = offset; 6105 } 6106 break; 6107 case 2: 6108 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6109 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6110 if (!continuous && d < dim) continue; 6111 /* The SEM order is 6112 6113 v_lb, {e_b}, v_rb, 6114 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6115 v_lt, reverse {e_t}, v_rt 6116 */ 6117 if (continuous) { 6118 const PetscInt of = 0; 6119 const PetscInt oeb = of + PetscSqr(k - 1); 6120 const PetscInt oer = oeb + (k - 1); 6121 const PetscInt oet = oer + (k - 1); 6122 const PetscInt oel = oet + (k - 1); 6123 const PetscInt ovlb = oel + (k - 1); 6124 const PetscInt ovrb = ovlb + 1; 6125 const PetscInt ovrt = ovrb + 1; 6126 const PetscInt ovlt = ovrt + 1; 6127 PetscInt o; 6128 6129 /* bottom */ 6130 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6131 for (o = oeb; o < oer; ++o) 6132 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6133 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6134 /* middle */ 6135 for (i = 0; i < k - 1; ++i) { 6136 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6137 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6138 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6139 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6140 } 6141 /* top */ 6142 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6143 for (o = oel - 1; o >= oet; --o) 6144 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6145 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6146 foffset = offset; 6147 } else { 6148 PetscInt dof; 6149 6150 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6151 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6152 foffset = offset; 6153 } 6154 break; 6155 case 3: 6156 /* The original hex closure is 6157 6158 {c, 6159 f_b, f_t, f_f, f_b, f_r, f_l, 6160 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6161 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6162 */ 6163 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6164 if (!continuous && d < dim) continue; 6165 /* The SEM order is 6166 Bottom Slice 6167 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6168 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6169 v_blb, {e_bb}, v_brb, 6170 6171 Middle Slice (j) 6172 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6173 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6174 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6175 6176 Top Slice 6177 v_tlf, {e_tf}, v_trf, 6178 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6179 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6180 */ 6181 if (continuous) { 6182 const PetscInt oc = 0; 6183 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6184 const PetscInt oft = ofb + PetscSqr(k - 1); 6185 const PetscInt off = oft + PetscSqr(k - 1); 6186 const PetscInt ofk = off + PetscSqr(k - 1); 6187 const PetscInt ofr = ofk + PetscSqr(k - 1); 6188 const PetscInt ofl = ofr + PetscSqr(k - 1); 6189 const PetscInt oebl = ofl + PetscSqr(k - 1); 6190 const PetscInt oebb = oebl + (k - 1); 6191 const PetscInt oebr = oebb + (k - 1); 6192 const PetscInt oebf = oebr + (k - 1); 6193 const PetscInt oetf = oebf + (k - 1); 6194 const PetscInt oetr = oetf + (k - 1); 6195 const PetscInt oetb = oetr + (k - 1); 6196 const PetscInt oetl = oetb + (k - 1); 6197 const PetscInt oerf = oetl + (k - 1); 6198 const PetscInt oelf = oerf + (k - 1); 6199 const PetscInt oelb = oelf + (k - 1); 6200 const PetscInt oerb = oelb + (k - 1); 6201 const PetscInt ovblf = oerb + (k - 1); 6202 const PetscInt ovblb = ovblf + 1; 6203 const PetscInt ovbrb = ovblb + 1; 6204 const PetscInt ovbrf = ovbrb + 1; 6205 const PetscInt ovtlf = ovbrf + 1; 6206 const PetscInt ovtrf = ovtlf + 1; 6207 const PetscInt ovtrb = ovtrf + 1; 6208 const PetscInt ovtlb = ovtrb + 1; 6209 PetscInt o, n; 6210 6211 /* Bottom Slice */ 6212 /* bottom */ 6213 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6214 for (o = oetf - 1; o >= oebf; --o) 6215 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6216 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6217 /* middle */ 6218 for (i = 0; i < k - 1; ++i) { 6219 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6220 for (n = 0; n < k - 1; ++n) { 6221 o = ofb + n * (k - 1) + i; 6222 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6223 } 6224 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6225 } 6226 /* top */ 6227 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6228 for (o = oebb; o < oebr; ++o) 6229 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6230 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6231 6232 /* Middle Slice */ 6233 for (j = 0; j < k - 1; ++j) { 6234 /* bottom */ 6235 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6236 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6237 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6238 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6239 /* middle */ 6240 for (i = 0; i < k - 1; ++i) { 6241 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6242 for (n = 0; n < k - 1; ++n) 6243 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6244 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6245 } 6246 /* top */ 6247 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6248 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6249 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6250 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6251 } 6252 6253 /* Top Slice */ 6254 /* bottom */ 6255 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6256 for (o = oetf; o < oetr; ++o) 6257 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6258 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6259 /* middle */ 6260 for (i = 0; i < k - 1; ++i) { 6261 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6262 for (n = 0; n < k - 1; ++n) 6263 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6264 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6265 } 6266 /* top */ 6267 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6268 for (o = oetl - 1; o >= oetb; --o) 6269 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6270 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6271 6272 foffset = offset; 6273 } else { 6274 PetscInt dof; 6275 6276 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6277 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6278 foffset = offset; 6279 } 6280 break; 6281 default: 6282 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6283 } 6284 } 6285 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6286 /* Check permutation */ 6287 { 6288 PetscInt *check; 6289 6290 PetscCall(PetscMalloc1(size, &check)); 6291 for (i = 0; i < size; ++i) { 6292 check[i] = -1; 6293 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6294 } 6295 for (i = 0; i < size; ++i) check[perm[i]] = i; 6296 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6297 PetscCall(PetscFree(check)); 6298 } 6299 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6300 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6301 PetscInt *loc_perm; 6302 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6303 for (PetscInt i = 0; i < size; i++) { 6304 loc_perm[i] = perm[i]; 6305 loc_perm[size + i] = size + perm[i]; 6306 } 6307 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6308 } 6309 } 6310 PetscFunctionReturn(PETSC_SUCCESS); 6311 } 6312 6313 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6314 { 6315 PetscDS prob; 6316 PetscInt depth, Nf, h; 6317 DMLabel label; 6318 6319 PetscFunctionBeginHot; 6320 PetscCall(DMGetDS(dm, &prob)); 6321 Nf = prob->Nf; 6322 label = dm->depthLabel; 6323 *dspace = NULL; 6324 if (field < Nf) { 6325 PetscObject disc = prob->disc[field]; 6326 6327 if (disc->classid == PETSCFE_CLASSID) { 6328 PetscDualSpace dsp; 6329 6330 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6331 PetscCall(DMLabelGetNumValues(label, &depth)); 6332 PetscCall(DMLabelGetValue(label, point, &h)); 6333 h = depth - 1 - h; 6334 if (h) { 6335 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6336 } else { 6337 *dspace = dsp; 6338 } 6339 } 6340 } 6341 PetscFunctionReturn(PETSC_SUCCESS); 6342 } 6343 6344 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6345 { 6346 PetscScalar *array; 6347 const PetscScalar *vArray; 6348 const PetscInt *cone, *coneO; 6349 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6350 6351 PetscFunctionBeginHot; 6352 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6353 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6354 PetscCall(DMPlexGetCone(dm, point, &cone)); 6355 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6356 if (!values || !*values) { 6357 if ((point >= pStart) && (point < pEnd)) { 6358 PetscInt dof; 6359 6360 PetscCall(PetscSectionGetDof(section, point, &dof)); 6361 size += dof; 6362 } 6363 for (p = 0; p < numPoints; ++p) { 6364 const PetscInt cp = cone[p]; 6365 PetscInt dof; 6366 6367 if ((cp < pStart) || (cp >= pEnd)) continue; 6368 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6369 size += dof; 6370 } 6371 if (!values) { 6372 if (csize) *csize = size; 6373 PetscFunctionReturn(PETSC_SUCCESS); 6374 } 6375 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6376 } else { 6377 array = *values; 6378 } 6379 size = 0; 6380 PetscCall(VecGetArrayRead(v, &vArray)); 6381 if ((point >= pStart) && (point < pEnd)) { 6382 PetscInt dof, off, d; 6383 const PetscScalar *varr; 6384 6385 PetscCall(PetscSectionGetDof(section, point, &dof)); 6386 PetscCall(PetscSectionGetOffset(section, point, &off)); 6387 varr = PetscSafePointerPlusOffset(vArray, off); 6388 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6389 size += dof; 6390 } 6391 for (p = 0; p < numPoints; ++p) { 6392 const PetscInt cp = cone[p]; 6393 PetscInt o = coneO[p]; 6394 PetscInt dof, off, d; 6395 const PetscScalar *varr; 6396 6397 if ((cp < pStart) || (cp >= pEnd)) continue; 6398 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6399 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6400 varr = PetscSafePointerPlusOffset(vArray, off); 6401 if (o >= 0) { 6402 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6403 } else { 6404 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6405 } 6406 size += dof; 6407 } 6408 PetscCall(VecRestoreArrayRead(v, &vArray)); 6409 if (!*values) { 6410 if (csize) *csize = size; 6411 *values = array; 6412 } else { 6413 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6414 *csize = size; 6415 } 6416 PetscFunctionReturn(PETSC_SUCCESS); 6417 } 6418 6419 /* Compress out points not in the section */ 6420 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6421 { 6422 const PetscInt np = *numPoints; 6423 PetscInt pStart, pEnd, p, q; 6424 6425 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6426 for (p = 0, q = 0; p < np; ++p) { 6427 const PetscInt r = points[p * 2]; 6428 if ((r >= pStart) && (r < pEnd)) { 6429 points[q * 2] = r; 6430 points[q * 2 + 1] = points[p * 2 + 1]; 6431 ++q; 6432 } 6433 } 6434 *numPoints = q; 6435 return PETSC_SUCCESS; 6436 } 6437 6438 /* Compressed closure does not apply closure permutation */ 6439 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6440 { 6441 const PetscInt *cla = NULL; 6442 PetscInt np, *pts = NULL; 6443 6444 PetscFunctionBeginHot; 6445 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6446 if (!ornt && *clPoints) { 6447 PetscInt dof, off; 6448 6449 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6450 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6451 PetscCall(ISGetIndices(*clPoints, &cla)); 6452 np = dof / 2; 6453 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6454 } else { 6455 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6456 PetscCall(CompressPoints_Private(section, &np, pts)); 6457 } 6458 *numPoints = np; 6459 *points = pts; 6460 *clp = cla; 6461 PetscFunctionReturn(PETSC_SUCCESS); 6462 } 6463 6464 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6465 { 6466 PetscFunctionBeginHot; 6467 if (!*clPoints) { 6468 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6469 } else { 6470 PetscCall(ISRestoreIndices(*clPoints, clp)); 6471 } 6472 *numPoints = 0; 6473 *points = NULL; 6474 *clSec = NULL; 6475 *clPoints = NULL; 6476 *clp = NULL; 6477 PetscFunctionReturn(PETSC_SUCCESS); 6478 } 6479 6480 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6481 { 6482 PetscInt offset = 0, p; 6483 const PetscInt **perms = NULL; 6484 const PetscScalar **flips = NULL; 6485 6486 PetscFunctionBeginHot; 6487 *size = 0; 6488 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6489 for (p = 0; p < numPoints; p++) { 6490 const PetscInt point = points[2 * p]; 6491 const PetscInt *perm = perms ? perms[p] : NULL; 6492 const PetscScalar *flip = flips ? flips[p] : NULL; 6493 PetscInt dof, off, d; 6494 const PetscScalar *varr; 6495 6496 PetscCall(PetscSectionGetDof(section, point, &dof)); 6497 PetscCall(PetscSectionGetOffset(section, point, &off)); 6498 varr = PetscSafePointerPlusOffset(vArray, off); 6499 if (clperm) { 6500 if (perm) { 6501 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6502 } else { 6503 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6504 } 6505 if (flip) { 6506 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6507 } 6508 } else { 6509 if (perm) { 6510 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6511 } else { 6512 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6513 } 6514 if (flip) { 6515 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6516 } 6517 } 6518 offset += dof; 6519 } 6520 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6521 *size = offset; 6522 PetscFunctionReturn(PETSC_SUCCESS); 6523 } 6524 6525 static inline PetscErrorCode DMPlexVecGetClosure_Fields_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6526 { 6527 PetscInt offset = 0, f; 6528 6529 PetscFunctionBeginHot; 6530 *size = 0; 6531 for (f = 0; f < numFields; ++f) { 6532 PetscInt p; 6533 const PetscInt **perms = NULL; 6534 const PetscScalar **flips = NULL; 6535 6536 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6537 for (p = 0; p < numPoints; p++) { 6538 const PetscInt point = points[2 * p]; 6539 PetscInt fdof, foff, b; 6540 const PetscScalar *varr; 6541 const PetscInt *perm = perms ? perms[p] : NULL; 6542 const PetscScalar *flip = flips ? flips[p] : NULL; 6543 6544 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6545 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6546 varr = &vArray[foff]; 6547 if (clperm) { 6548 if (perm) { 6549 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6550 } else { 6551 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6552 } 6553 if (flip) { 6554 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6555 } 6556 } else { 6557 if (perm) { 6558 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6559 } else { 6560 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6561 } 6562 if (flip) { 6563 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6564 } 6565 } 6566 offset += fdof; 6567 } 6568 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6569 } 6570 *size = offset; 6571 PetscFunctionReturn(PETSC_SUCCESS); 6572 } 6573 6574 /*@C 6575 DMPlexVecGetOrientedClosure - Get an array of the values on the closure of 'point' with a given orientation, optionally applying the closure permutation. 6576 6577 Not collective 6578 6579 Input Parameters: 6580 + dm - The `DM` 6581 . section - The section describing the layout in `v`, or `NULL` to use the default section 6582 . useClPerm - Flag for whether the provided closure permutation should be applied to the values 6583 . v - The local vector 6584 . point - The point in the `DM` 6585 - ornt - The orientation of the cell, an integer giving the prescription for cone traversal. Typically, this will be 0. 6586 6587 Input/Output Parameters: 6588 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6589 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6590 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6591 6592 Level: advanced 6593 6594 Notes: 6595 `DMPlexVecGetOrientedClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6596 calling function. This is because `DMPlexVecGetOrientedClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6597 assembly function, and a user may already have allocated storage for this operation. 6598 6599 Fortran Notes: 6600 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6601 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6602 6603 `values` must be declared with 6604 .vb 6605 PetscScalar,dimension(:),pointer :: values 6606 .ve 6607 and it will be allocated internally by PETSc to hold the values returned 6608 6609 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexGetCellCoordinates()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()` 6610 @*/ 6611 PetscErrorCode DMPlexVecGetOrientedClosure(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6612 { 6613 PetscSection clSection; 6614 IS clPoints; 6615 PetscInt *points = NULL; 6616 const PetscInt *clp, *perm = NULL; 6617 PetscInt depth, numFields, numPoints, asize; 6618 6619 PetscFunctionBeginHot; 6620 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6621 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6622 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6623 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6624 PetscCall(DMPlexGetDepth(dm, &depth)); 6625 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6626 if (depth == 1 && numFields < 2) { 6627 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6628 PetscFunctionReturn(PETSC_SUCCESS); 6629 } 6630 /* Get points */ 6631 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6632 /* Get sizes */ 6633 asize = 0; 6634 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6635 PetscInt dof; 6636 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6637 asize += dof; 6638 } 6639 if (values) { 6640 const PetscScalar *vArray; 6641 PetscInt size; 6642 6643 if (*values) { 6644 PetscCheck(*csize >= asize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %" PetscInt_FMT " not sufficient to hold closure size %" PetscInt_FMT, *csize, asize); 6645 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6646 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6647 PetscCall(VecGetArrayRead(v, &vArray)); 6648 /* Get values */ 6649 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6650 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6651 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6652 /* Cleanup array */ 6653 PetscCall(VecRestoreArrayRead(v, &vArray)); 6654 } 6655 if (csize) *csize = asize; 6656 /* Cleanup points */ 6657 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6658 PetscFunctionReturn(PETSC_SUCCESS); 6659 } 6660 6661 /*@C 6662 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6663 6664 Not collective 6665 6666 Input Parameters: 6667 + dm - The `DM` 6668 . section - The section describing the layout in `v`, or `NULL` to use the default section 6669 . v - The local vector 6670 - point - The point in the `DM` 6671 6672 Input/Output Parameters: 6673 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6674 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6675 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6676 6677 Level: intermediate 6678 6679 Notes: 6680 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6681 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6682 assembly function, and a user may already have allocated storage for this operation. 6683 6684 A typical use could be 6685 .vb 6686 values = NULL; 6687 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6688 for (cl = 0; cl < clSize; ++cl) { 6689 <Compute on closure> 6690 } 6691 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6692 .ve 6693 or 6694 .vb 6695 PetscMalloc1(clMaxSize, &values); 6696 for (p = pStart; p < pEnd; ++p) { 6697 clSize = clMaxSize; 6698 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6699 for (cl = 0; cl < clSize; ++cl) { 6700 <Compute on closure> 6701 } 6702 } 6703 PetscFree(values); 6704 .ve 6705 6706 Fortran Notes: 6707 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6708 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6709 6710 `values` must be declared with 6711 .vb 6712 PetscScalar,dimension(:),pointer :: values 6713 .ve 6714 and it will be allocated internally by PETSc to hold the values returned 6715 6716 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6717 @*/ 6718 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6719 { 6720 PetscFunctionBeginHot; 6721 PetscCall(DMPlexVecGetOrientedClosure(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6722 PetscFunctionReturn(PETSC_SUCCESS); 6723 } 6724 6725 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6726 { 6727 DMLabel depthLabel; 6728 PetscSection clSection; 6729 IS clPoints; 6730 PetscScalar *array; 6731 const PetscScalar *vArray; 6732 PetscInt *points = NULL; 6733 const PetscInt *clp, *perm = NULL; 6734 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6735 6736 PetscFunctionBeginHot; 6737 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6738 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6739 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6740 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6741 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6742 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6743 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6744 if (mdepth == 1 && numFields < 2) { 6745 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6746 PetscFunctionReturn(PETSC_SUCCESS); 6747 } 6748 /* Get points */ 6749 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6750 for (clsize = 0, p = 0; p < Np; p++) { 6751 PetscInt dof; 6752 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6753 clsize += dof; 6754 } 6755 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6756 /* Filter points */ 6757 for (p = 0; p < numPoints * 2; p += 2) { 6758 PetscInt dep; 6759 6760 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6761 if (dep != depth) continue; 6762 points[Np * 2 + 0] = points[p]; 6763 points[Np * 2 + 1] = points[p + 1]; 6764 ++Np; 6765 } 6766 /* Get array */ 6767 if (!values || !*values) { 6768 PetscInt asize = 0, dof; 6769 6770 for (p = 0; p < Np * 2; p += 2) { 6771 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6772 asize += dof; 6773 } 6774 if (!values) { 6775 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6776 if (csize) *csize = asize; 6777 PetscFunctionReturn(PETSC_SUCCESS); 6778 } 6779 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6780 } else { 6781 array = *values; 6782 } 6783 PetscCall(VecGetArrayRead(v, &vArray)); 6784 /* Get values */ 6785 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6786 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6787 /* Cleanup points */ 6788 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6789 /* Cleanup array */ 6790 PetscCall(VecRestoreArrayRead(v, &vArray)); 6791 if (!*values) { 6792 if (csize) *csize = size; 6793 *values = array; 6794 } else { 6795 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6796 *csize = size; 6797 } 6798 PetscFunctionReturn(PETSC_SUCCESS); 6799 } 6800 6801 /*@C 6802 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6803 6804 Not collective 6805 6806 Input Parameters: 6807 + dm - The `DM` 6808 . section - The section describing the layout in `v`, or `NULL` to use the default section 6809 . v - The local vector 6810 . point - The point in the `DM` 6811 . csize - The number of values in the closure, or `NULL` 6812 - values - The array of values 6813 6814 Level: intermediate 6815 6816 Note: 6817 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6818 6819 Fortran Note: 6820 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6821 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6822 6823 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6824 @*/ 6825 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6826 { 6827 PetscInt size = 0; 6828 6829 PetscFunctionBegin; 6830 /* Should work without recalculating size */ 6831 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6832 *values = NULL; 6833 PetscFunctionReturn(PETSC_SUCCESS); 6834 } 6835 6836 static inline void add(PetscScalar *x, PetscScalar y) 6837 { 6838 *x += y; 6839 } 6840 static inline void insert(PetscScalar *x, PetscScalar y) 6841 { 6842 *x = y; 6843 } 6844 6845 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[]) 6846 { 6847 PetscInt cdof; /* The number of constraints on this point */ 6848 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6849 PetscScalar *a; 6850 PetscInt off, cind = 0, k; 6851 6852 PetscFunctionBegin; 6853 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6854 PetscCall(PetscSectionGetOffset(section, point, &off)); 6855 a = &array[off]; 6856 if (!cdof || setBC) { 6857 if (clperm) { 6858 if (perm) { 6859 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6860 } else { 6861 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6862 } 6863 } else { 6864 if (perm) { 6865 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6866 } else { 6867 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6868 } 6869 } 6870 } else { 6871 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6872 if (clperm) { 6873 if (perm) { 6874 for (k = 0; k < dof; ++k) { 6875 if ((cind < cdof) && (k == cdofs[cind])) { 6876 ++cind; 6877 continue; 6878 } 6879 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6880 } 6881 } else { 6882 for (k = 0; k < dof; ++k) { 6883 if ((cind < cdof) && (k == cdofs[cind])) { 6884 ++cind; 6885 continue; 6886 } 6887 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6888 } 6889 } 6890 } else { 6891 if (perm) { 6892 for (k = 0; k < dof; ++k) { 6893 if ((cind < cdof) && (k == cdofs[cind])) { 6894 ++cind; 6895 continue; 6896 } 6897 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6898 } 6899 } else { 6900 for (k = 0; k < dof; ++k) { 6901 if ((cind < cdof) && (k == cdofs[cind])) { 6902 ++cind; 6903 continue; 6904 } 6905 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6906 } 6907 } 6908 } 6909 } 6910 PetscFunctionReturn(PETSC_SUCCESS); 6911 } 6912 6913 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[]) 6914 { 6915 PetscInt cdof; /* The number of constraints on this point */ 6916 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6917 PetscScalar *a; 6918 PetscInt off, cind = 0, k; 6919 6920 PetscFunctionBegin; 6921 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6922 PetscCall(PetscSectionGetOffset(section, point, &off)); 6923 a = &array[off]; 6924 if (cdof) { 6925 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6926 if (clperm) { 6927 if (perm) { 6928 for (k = 0; k < dof; ++k) { 6929 if ((cind < cdof) && (k == cdofs[cind])) { 6930 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6931 cind++; 6932 } 6933 } 6934 } else { 6935 for (k = 0; k < dof; ++k) { 6936 if ((cind < cdof) && (k == cdofs[cind])) { 6937 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6938 cind++; 6939 } 6940 } 6941 } 6942 } else { 6943 if (perm) { 6944 for (k = 0; k < dof; ++k) { 6945 if ((cind < cdof) && (k == cdofs[cind])) { 6946 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6947 cind++; 6948 } 6949 } 6950 } else { 6951 for (k = 0; k < dof; ++k) { 6952 if ((cind < cdof) && (k == cdofs[cind])) { 6953 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6954 cind++; 6955 } 6956 } 6957 } 6958 } 6959 } 6960 PetscFunctionReturn(PETSC_SUCCESS); 6961 } 6962 6963 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[]) 6964 { 6965 PetscScalar *a; 6966 PetscInt fdof, foff, fcdof, foffset = *offset; 6967 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6968 PetscInt cind = 0, b; 6969 6970 PetscFunctionBegin; 6971 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6972 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6973 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6974 a = &array[foff]; 6975 if (!fcdof || setBC) { 6976 if (clperm) { 6977 if (perm) { 6978 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6979 } else { 6980 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6981 } 6982 } else { 6983 if (perm) { 6984 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6985 } else { 6986 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6987 } 6988 } 6989 } else { 6990 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6991 if (clperm) { 6992 if (perm) { 6993 for (b = 0; b < fdof; b++) { 6994 if ((cind < fcdof) && (b == fcdofs[cind])) { 6995 ++cind; 6996 continue; 6997 } 6998 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6999 } 7000 } else { 7001 for (b = 0; b < fdof; b++) { 7002 if ((cind < fcdof) && (b == fcdofs[cind])) { 7003 ++cind; 7004 continue; 7005 } 7006 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7007 } 7008 } 7009 } else { 7010 if (perm) { 7011 for (b = 0; b < fdof; b++) { 7012 if ((cind < fcdof) && (b == fcdofs[cind])) { 7013 ++cind; 7014 continue; 7015 } 7016 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7017 } 7018 } else { 7019 for (b = 0; b < fdof; b++) { 7020 if ((cind < fcdof) && (b == fcdofs[cind])) { 7021 ++cind; 7022 continue; 7023 } 7024 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7025 } 7026 } 7027 } 7028 } 7029 *offset += fdof; 7030 PetscFunctionReturn(PETSC_SUCCESS); 7031 } 7032 7033 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[]) 7034 { 7035 PetscScalar *a; 7036 PetscInt fdof, foff, fcdof, foffset = *offset; 7037 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7038 PetscInt Nc, cind = 0, ncind = 0, b; 7039 PetscBool ncSet, fcSet; 7040 7041 PetscFunctionBegin; 7042 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 7043 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7044 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 7045 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 7046 a = &array[foff]; 7047 if (fcdof) { 7048 /* We just override fcdof and fcdofs with Ncc and comps */ 7049 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7050 if (clperm) { 7051 if (perm) { 7052 if (comps) { 7053 for (b = 0; b < fdof; b++) { 7054 ncSet = fcSet = PETSC_FALSE; 7055 if (b % Nc == comps[ncind]) { 7056 ncind = (ncind + 1) % Ncc; 7057 ncSet = PETSC_TRUE; 7058 } 7059 if ((cind < fcdof) && (b == fcdofs[cind])) { 7060 ++cind; 7061 fcSet = PETSC_TRUE; 7062 } 7063 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7064 } 7065 } else { 7066 for (b = 0; b < fdof; b++) { 7067 if ((cind < fcdof) && (b == fcdofs[cind])) { 7068 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7069 ++cind; 7070 } 7071 } 7072 } 7073 } else { 7074 if (comps) { 7075 for (b = 0; b < fdof; b++) { 7076 ncSet = fcSet = PETSC_FALSE; 7077 if (b % Nc == comps[ncind]) { 7078 ncind = (ncind + 1) % Ncc; 7079 ncSet = PETSC_TRUE; 7080 } 7081 if ((cind < fcdof) && (b == fcdofs[cind])) { 7082 ++cind; 7083 fcSet = PETSC_TRUE; 7084 } 7085 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7086 } 7087 } else { 7088 for (b = 0; b < fdof; b++) { 7089 if ((cind < fcdof) && (b == fcdofs[cind])) { 7090 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7091 ++cind; 7092 } 7093 } 7094 } 7095 } 7096 } else { 7097 if (perm) { 7098 if (comps) { 7099 for (b = 0; b < fdof; b++) { 7100 ncSet = fcSet = PETSC_FALSE; 7101 if (b % Nc == comps[ncind]) { 7102 ncind = (ncind + 1) % Ncc; 7103 ncSet = PETSC_TRUE; 7104 } 7105 if ((cind < fcdof) && (b == fcdofs[cind])) { 7106 ++cind; 7107 fcSet = PETSC_TRUE; 7108 } 7109 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7110 } 7111 } else { 7112 for (b = 0; b < fdof; b++) { 7113 if ((cind < fcdof) && (b == fcdofs[cind])) { 7114 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7115 ++cind; 7116 } 7117 } 7118 } 7119 } else { 7120 if (comps) { 7121 for (b = 0; b < fdof; b++) { 7122 ncSet = fcSet = PETSC_FALSE; 7123 if (b % Nc == comps[ncind]) { 7124 ncind = (ncind + 1) % Ncc; 7125 ncSet = PETSC_TRUE; 7126 } 7127 if ((cind < fcdof) && (b == fcdofs[cind])) { 7128 ++cind; 7129 fcSet = PETSC_TRUE; 7130 } 7131 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7132 } 7133 } else { 7134 for (b = 0; b < fdof; b++) { 7135 if ((cind < fcdof) && (b == fcdofs[cind])) { 7136 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7137 ++cind; 7138 } 7139 } 7140 } 7141 } 7142 } 7143 } 7144 *offset += fdof; 7145 PetscFunctionReturn(PETSC_SUCCESS); 7146 } 7147 7148 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7149 { 7150 PetscScalar *array; 7151 const PetscInt *cone, *coneO; 7152 PetscInt pStart, pEnd, p, numPoints, off, dof; 7153 7154 PetscFunctionBeginHot; 7155 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7156 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7157 PetscCall(DMPlexGetCone(dm, point, &cone)); 7158 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7159 PetscCall(VecGetArray(v, &array)); 7160 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7161 const PetscInt cp = !p ? point : cone[p - 1]; 7162 const PetscInt o = !p ? 0 : coneO[p - 1]; 7163 7164 if ((cp < pStart) || (cp >= pEnd)) { 7165 dof = 0; 7166 continue; 7167 } 7168 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7169 /* ADD_VALUES */ 7170 { 7171 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7172 PetscScalar *a; 7173 PetscInt cdof, coff, cind = 0, k; 7174 7175 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7176 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7177 a = &array[coff]; 7178 if (!cdof) { 7179 if (o >= 0) { 7180 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7181 } else { 7182 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7183 } 7184 } else { 7185 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7186 if (o >= 0) { 7187 for (k = 0; k < dof; ++k) { 7188 if ((cind < cdof) && (k == cdofs[cind])) { 7189 ++cind; 7190 continue; 7191 } 7192 a[k] += values[off + k]; 7193 } 7194 } else { 7195 for (k = 0; k < dof; ++k) { 7196 if ((cind < cdof) && (k == cdofs[cind])) { 7197 ++cind; 7198 continue; 7199 } 7200 a[k] += values[off + dof - k - 1]; 7201 } 7202 } 7203 } 7204 } 7205 } 7206 PetscCall(VecRestoreArray(v, &array)); 7207 PetscFunctionReturn(PETSC_SUCCESS); 7208 } 7209 7210 /*@C 7211 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7212 7213 Not collective 7214 7215 Input Parameters: 7216 + dm - The `DM` 7217 . section - The section describing the layout in `v`, or `NULL` to use the default section 7218 . v - The local vector 7219 . point - The point in the `DM` 7220 . values - The array of values 7221 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7222 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7223 7224 Level: intermediate 7225 7226 Note: 7227 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7228 7229 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7230 @*/ 7231 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7232 { 7233 PetscSection clSection; 7234 IS clPoints; 7235 PetscScalar *array; 7236 PetscInt *points = NULL; 7237 const PetscInt *clp, *clperm = NULL; 7238 PetscInt depth, numFields, numPoints, p, clsize; 7239 7240 PetscFunctionBeginHot; 7241 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7242 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7243 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7244 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7245 PetscCall(DMPlexGetDepth(dm, &depth)); 7246 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7247 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7248 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7249 PetscFunctionReturn(PETSC_SUCCESS); 7250 } 7251 /* Get points */ 7252 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7253 for (clsize = 0, p = 0; p < numPoints; p++) { 7254 PetscInt dof; 7255 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7256 clsize += dof; 7257 } 7258 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7259 /* Get array */ 7260 PetscCall(VecGetArray(v, &array)); 7261 /* Get values */ 7262 if (numFields > 0) { 7263 PetscInt offset = 0, f; 7264 for (f = 0; f < numFields; ++f) { 7265 const PetscInt **perms = NULL; 7266 const PetscScalar **flips = NULL; 7267 7268 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7269 switch (mode) { 7270 case INSERT_VALUES: 7271 for (p = 0; p < numPoints; p++) { 7272 const PetscInt point = points[2 * p]; 7273 const PetscInt *perm = perms ? perms[p] : NULL; 7274 const PetscScalar *flip = flips ? flips[p] : NULL; 7275 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7276 } 7277 break; 7278 case INSERT_ALL_VALUES: 7279 for (p = 0; p < numPoints; p++) { 7280 const PetscInt point = points[2 * p]; 7281 const PetscInt *perm = perms ? perms[p] : NULL; 7282 const PetscScalar *flip = flips ? flips[p] : NULL; 7283 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7284 } 7285 break; 7286 case INSERT_BC_VALUES: 7287 for (p = 0; p < numPoints; p++) { 7288 const PetscInt point = points[2 * p]; 7289 const PetscInt *perm = perms ? perms[p] : NULL; 7290 const PetscScalar *flip = flips ? flips[p] : NULL; 7291 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7292 } 7293 break; 7294 case ADD_VALUES: 7295 for (p = 0; p < numPoints; p++) { 7296 const PetscInt point = points[2 * p]; 7297 const PetscInt *perm = perms ? perms[p] : NULL; 7298 const PetscScalar *flip = flips ? flips[p] : NULL; 7299 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7300 } 7301 break; 7302 case ADD_ALL_VALUES: 7303 for (p = 0; p < numPoints; p++) { 7304 const PetscInt point = points[2 * p]; 7305 const PetscInt *perm = perms ? perms[p] : NULL; 7306 const PetscScalar *flip = flips ? flips[p] : NULL; 7307 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7308 } 7309 break; 7310 case ADD_BC_VALUES: 7311 for (p = 0; p < numPoints; p++) { 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(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7316 } 7317 break; 7318 default: 7319 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7320 } 7321 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7322 } 7323 } else { 7324 PetscInt dof, off; 7325 const PetscInt **perms = NULL; 7326 const PetscScalar **flips = NULL; 7327 7328 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7329 switch (mode) { 7330 case INSERT_VALUES: 7331 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7332 const PetscInt point = points[2 * p]; 7333 const PetscInt *perm = perms ? perms[p] : NULL; 7334 const PetscScalar *flip = flips ? flips[p] : NULL; 7335 PetscCall(PetscSectionGetDof(section, point, &dof)); 7336 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7337 } 7338 break; 7339 case INSERT_ALL_VALUES: 7340 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7341 const PetscInt point = points[2 * p]; 7342 const PetscInt *perm = perms ? perms[p] : NULL; 7343 const PetscScalar *flip = flips ? flips[p] : NULL; 7344 PetscCall(PetscSectionGetDof(section, point, &dof)); 7345 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7346 } 7347 break; 7348 case INSERT_BC_VALUES: 7349 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7350 const PetscInt point = points[2 * p]; 7351 const PetscInt *perm = perms ? perms[p] : NULL; 7352 const PetscScalar *flip = flips ? flips[p] : NULL; 7353 PetscCall(PetscSectionGetDof(section, point, &dof)); 7354 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7355 } 7356 break; 7357 case ADD_VALUES: 7358 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7359 const PetscInt point = points[2 * p]; 7360 const PetscInt *perm = perms ? perms[p] : NULL; 7361 const PetscScalar *flip = flips ? flips[p] : NULL; 7362 PetscCall(PetscSectionGetDof(section, point, &dof)); 7363 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7364 } 7365 break; 7366 case ADD_ALL_VALUES: 7367 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7368 const PetscInt point = points[2 * p]; 7369 const PetscInt *perm = perms ? perms[p] : NULL; 7370 const PetscScalar *flip = flips ? flips[p] : NULL; 7371 PetscCall(PetscSectionGetDof(section, point, &dof)); 7372 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7373 } 7374 break; 7375 case ADD_BC_VALUES: 7376 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7377 const PetscInt point = points[2 * p]; 7378 const PetscInt *perm = perms ? perms[p] : NULL; 7379 const PetscScalar *flip = flips ? flips[p] : NULL; 7380 PetscCall(PetscSectionGetDof(section, point, &dof)); 7381 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7382 } 7383 break; 7384 default: 7385 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7386 } 7387 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7388 } 7389 /* Cleanup points */ 7390 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7391 /* Cleanup array */ 7392 PetscCall(VecRestoreArray(v, &array)); 7393 PetscFunctionReturn(PETSC_SUCCESS); 7394 } 7395 7396 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7397 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7398 { 7399 PetscFunctionBegin; 7400 *contains = PETSC_TRUE; 7401 if (label) { 7402 PetscInt fdof; 7403 7404 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7405 if (!*contains) { 7406 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7407 *offset += fdof; 7408 PetscFunctionReturn(PETSC_SUCCESS); 7409 } 7410 } 7411 PetscFunctionReturn(PETSC_SUCCESS); 7412 } 7413 7414 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7415 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) 7416 { 7417 PetscSection clSection; 7418 IS clPoints; 7419 PetscScalar *array; 7420 PetscInt *points = NULL; 7421 const PetscInt *clp; 7422 PetscInt numFields, numPoints, p; 7423 PetscInt offset = 0, f; 7424 7425 PetscFunctionBeginHot; 7426 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7427 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7428 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7429 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7430 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7431 /* Get points */ 7432 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7433 /* Get array */ 7434 PetscCall(VecGetArray(v, &array)); 7435 /* Get values */ 7436 for (f = 0; f < numFields; ++f) { 7437 const PetscInt **perms = NULL; 7438 const PetscScalar **flips = NULL; 7439 PetscBool contains; 7440 7441 if (!fieldActive[f]) { 7442 for (p = 0; p < numPoints * 2; p += 2) { 7443 PetscInt fdof; 7444 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7445 offset += fdof; 7446 } 7447 continue; 7448 } 7449 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7450 switch (mode) { 7451 case INSERT_VALUES: 7452 for (p = 0; p < numPoints; p++) { 7453 const PetscInt point = points[2 * p]; 7454 const PetscInt *perm = perms ? perms[p] : NULL; 7455 const PetscScalar *flip = flips ? flips[p] : NULL; 7456 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7457 if (!contains) continue; 7458 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7459 } 7460 break; 7461 case INSERT_ALL_VALUES: 7462 for (p = 0; p < numPoints; p++) { 7463 const PetscInt point = points[2 * p]; 7464 const PetscInt *perm = perms ? perms[p] : NULL; 7465 const PetscScalar *flip = flips ? flips[p] : NULL; 7466 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7467 if (!contains) continue; 7468 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7469 } 7470 break; 7471 case INSERT_BC_VALUES: 7472 for (p = 0; p < numPoints; p++) { 7473 const PetscInt point = points[2 * p]; 7474 const PetscInt *perm = perms ? perms[p] : NULL; 7475 const PetscScalar *flip = flips ? flips[p] : NULL; 7476 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7477 if (!contains) continue; 7478 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7479 } 7480 break; 7481 case ADD_VALUES: 7482 for (p = 0; p < numPoints; p++) { 7483 const PetscInt point = points[2 * p]; 7484 const PetscInt *perm = perms ? perms[p] : NULL; 7485 const PetscScalar *flip = flips ? flips[p] : NULL; 7486 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7487 if (!contains) continue; 7488 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7489 } 7490 break; 7491 case ADD_ALL_VALUES: 7492 for (p = 0; p < numPoints; p++) { 7493 const PetscInt point = points[2 * p]; 7494 const PetscInt *perm = perms ? perms[p] : NULL; 7495 const PetscScalar *flip = flips ? flips[p] : NULL; 7496 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7497 if (!contains) continue; 7498 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7499 } 7500 break; 7501 default: 7502 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7503 } 7504 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7505 } 7506 /* Cleanup points */ 7507 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7508 /* Cleanup array */ 7509 PetscCall(VecRestoreArray(v, &array)); 7510 PetscFunctionReturn(PETSC_SUCCESS); 7511 } 7512 7513 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7514 { 7515 PetscMPIInt rank; 7516 PetscInt i, j; 7517 7518 PetscFunctionBegin; 7519 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7520 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7521 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7522 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7523 numCIndices = numCIndices ? numCIndices : numRIndices; 7524 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7525 for (i = 0; i < numRIndices; i++) { 7526 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7527 for (j = 0; j < numCIndices; j++) { 7528 #if defined(PETSC_USE_COMPLEX) 7529 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7530 #else 7531 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7532 #endif 7533 } 7534 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7535 } 7536 PetscFunctionReturn(PETSC_SUCCESS); 7537 } 7538 7539 /* 7540 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7541 7542 Input Parameters: 7543 + section - The section for this data layout 7544 . islocal - Is the section (and thus indices being requested) local or global? 7545 . point - The point contributing dofs with these indices 7546 . off - The global offset of this point 7547 . loff - The local offset of each field 7548 . setBC - The flag determining whether to include indices of boundary values 7549 . perm - A permutation of the dofs on this point, or NULL 7550 - indperm - A permutation of the entire indices array, or NULL 7551 7552 Output Parameter: 7553 . indices - Indices for dofs on this point 7554 7555 Level: developer 7556 7557 Note: The indices could be local or global, depending on the value of 'off'. 7558 */ 7559 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7560 { 7561 PetscInt dof; /* The number of unknowns on this point */ 7562 PetscInt cdof; /* The number of constraints on this point */ 7563 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7564 PetscInt cind = 0, k; 7565 7566 PetscFunctionBegin; 7567 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7568 PetscCall(PetscSectionGetDof(section, point, &dof)); 7569 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7570 if (!cdof || setBC) { 7571 for (k = 0; k < dof; ++k) { 7572 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7573 const PetscInt ind = indperm ? indperm[preind] : preind; 7574 7575 indices[ind] = off + k; 7576 } 7577 } else { 7578 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7579 for (k = 0; k < dof; ++k) { 7580 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7581 const PetscInt ind = indperm ? indperm[preind] : preind; 7582 7583 if ((cind < cdof) && (k == cdofs[cind])) { 7584 /* Insert check for returning constrained indices */ 7585 indices[ind] = -(off + k + 1); 7586 ++cind; 7587 } else { 7588 indices[ind] = off + k - (islocal ? 0 : cind); 7589 } 7590 } 7591 } 7592 *loff += dof; 7593 PetscFunctionReturn(PETSC_SUCCESS); 7594 } 7595 7596 /* 7597 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7598 7599 Input Parameters: 7600 + section - a section (global or local) 7601 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7602 . point - point within section 7603 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7604 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7605 . setBC - identify constrained (boundary condition) points via involution. 7606 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7607 . permsoff - offset 7608 - indperm - index permutation 7609 7610 Output Parameter: 7611 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7612 . indices - array to hold indices (as defined by section) of each dof associated with point 7613 7614 Notes: 7615 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7616 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7617 in the local vector. 7618 7619 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7620 significant). It is invalid to call with a global section and setBC=true. 7621 7622 Developer Note: 7623 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7624 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7625 offset could be obtained from the section instead of passing it explicitly as we do now. 7626 7627 Example: 7628 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7629 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7630 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7631 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. 7632 7633 Level: developer 7634 */ 7635 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[]) 7636 { 7637 PetscInt numFields, foff, f; 7638 7639 PetscFunctionBegin; 7640 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7641 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7642 for (f = 0, foff = 0; f < numFields; ++f) { 7643 PetscInt fdof, cfdof; 7644 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7645 PetscInt cind = 0, b; 7646 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7647 7648 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7649 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7650 if (!cfdof || setBC) { 7651 for (b = 0; b < fdof; ++b) { 7652 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7653 const PetscInt ind = indperm ? indperm[preind] : preind; 7654 7655 indices[ind] = off + foff + b; 7656 } 7657 } else { 7658 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7659 for (b = 0; b < fdof; ++b) { 7660 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7661 const PetscInt ind = indperm ? indperm[preind] : preind; 7662 7663 if ((cind < cfdof) && (b == fcdofs[cind])) { 7664 indices[ind] = -(off + foff + b + 1); 7665 ++cind; 7666 } else { 7667 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7668 } 7669 } 7670 } 7671 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7672 foffs[f] += fdof; 7673 } 7674 PetscFunctionReturn(PETSC_SUCCESS); 7675 } 7676 7677 /* 7678 This version believes the globalSection offsets for each field, rather than just the point offset 7679 7680 . foffs - The offset into 'indices' for each field, since it is segregated by field 7681 7682 Notes: 7683 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7684 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7685 */ 7686 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7687 { 7688 PetscInt numFields, foff, f; 7689 7690 PetscFunctionBegin; 7691 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7692 for (f = 0; f < numFields; ++f) { 7693 PetscInt fdof, cfdof; 7694 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7695 PetscInt cind = 0, b; 7696 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7697 7698 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7699 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7700 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7701 if (!cfdof) { 7702 for (b = 0; b < fdof; ++b) { 7703 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7704 const PetscInt ind = indperm ? indperm[preind] : preind; 7705 7706 indices[ind] = foff + b; 7707 } 7708 } else { 7709 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7710 for (b = 0; b < fdof; ++b) { 7711 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7712 const PetscInt ind = indperm ? indperm[preind] : preind; 7713 7714 if ((cind < cfdof) && (b == fcdofs[cind])) { 7715 indices[ind] = -(foff + b + 1); 7716 ++cind; 7717 } else { 7718 indices[ind] = foff + b - cind; 7719 } 7720 } 7721 } 7722 foffs[f] += fdof; 7723 } 7724 PetscFunctionReturn(PETSC_SUCCESS); 7725 } 7726 7727 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7728 { 7729 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7730 7731 PetscFunctionBegin; 7732 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7733 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7734 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7735 for (PetscInt p = 0; p < nPoints; p++) { 7736 PetscInt b = pnts[2 * p]; 7737 PetscInt bSecDof = 0, bOff; 7738 PetscInt cSecDof = 0; 7739 PetscSection indices_section; 7740 7741 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7742 if (!bSecDof) continue; 7743 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7744 indices_section = cSecDof > 0 ? cSec : section; 7745 if (numFields) { 7746 PetscInt fStart[32], fEnd[32]; 7747 7748 fStart[0] = 0; 7749 fEnd[0] = 0; 7750 for (PetscInt f = 0; f < numFields; f++) { 7751 PetscInt fDof = 0; 7752 7753 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7754 fStart[f + 1] = fStart[f] + fDof; 7755 fEnd[f + 1] = fStart[f + 1]; 7756 } 7757 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7758 // only apply permutations on one side 7759 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7760 for (PetscInt f = 0; f < numFields; f++) { 7761 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7762 } 7763 } else { 7764 PetscInt bEnd = 0; 7765 7766 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7767 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7768 7769 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7770 } 7771 } 7772 PetscFunctionReturn(PETSC_SUCCESS); 7773 } 7774 7775 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[]) 7776 { 7777 Mat cMat; 7778 PetscSection aSec, cSec; 7779 IS aIS; 7780 PetscInt aStart = -1, aEnd = -1; 7781 PetscInt sStart = -1, sEnd = -1; 7782 PetscInt cStart = -1, cEnd = -1; 7783 const PetscInt *anchors; 7784 PetscInt numFields, p; 7785 PetscInt newNumPoints = 0, newNumIndices = 0; 7786 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7787 PetscInt oldOffsets[32]; 7788 PetscInt newOffsets[32]; 7789 PetscInt oldOffsetsCopy[32]; 7790 PetscInt newOffsetsCopy[32]; 7791 PetscScalar *modMat = NULL; 7792 PetscBool anyConstrained = PETSC_FALSE; 7793 7794 PetscFunctionBegin; 7795 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7796 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7797 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7798 7799 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7800 /* if there are point-to-point constraints */ 7801 if (aSec) { 7802 PetscCall(PetscArrayzero(newOffsets, 32)); 7803 PetscCall(PetscArrayzero(oldOffsets, 32)); 7804 PetscCall(ISGetIndices(aIS, &anchors)); 7805 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7806 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7807 /* figure out how many points are going to be in the new element matrix 7808 * (we allow double counting, because it's all just going to be summed 7809 * into the global matrix anyway) */ 7810 for (p = 0; p < 2 * numPoints; p += 2) { 7811 PetscInt b = points[p]; 7812 PetscInt bDof = 0, bSecDof = 0; 7813 7814 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7815 if (!bSecDof) continue; 7816 7817 for (PetscInt f = 0; f < numFields; f++) { 7818 PetscInt fDof = 0; 7819 7820 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7821 oldOffsets[f + 1] += fDof; 7822 } 7823 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7824 if (bDof) { 7825 /* this point is constrained */ 7826 /* it is going to be replaced by its anchors */ 7827 PetscInt bOff, q; 7828 7829 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7830 for (q = 0; q < bDof; q++) { 7831 PetscInt a = anchors[bOff + q]; 7832 PetscInt aDof = 0; 7833 7834 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7835 if (aDof) { 7836 anyConstrained = PETSC_TRUE; 7837 newNumPoints += 1; 7838 } 7839 newNumIndices += aDof; 7840 for (PetscInt f = 0; f < numFields; ++f) { 7841 PetscInt fDof = 0; 7842 7843 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7844 newOffsets[f + 1] += fDof; 7845 } 7846 } 7847 } else { 7848 /* this point is not constrained */ 7849 newNumPoints++; 7850 newNumIndices += bSecDof; 7851 for (PetscInt f = 0; f < numFields; ++f) { 7852 PetscInt fDof; 7853 7854 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7855 newOffsets[f + 1] += fDof; 7856 } 7857 } 7858 } 7859 } 7860 if (!anyConstrained) { 7861 if (outNumPoints) *outNumPoints = 0; 7862 if (outNumIndices) *outNumIndices = 0; 7863 if (outPoints) *outPoints = NULL; 7864 if (outMat) *outMat = NULL; 7865 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7866 PetscFunctionReturn(PETSC_SUCCESS); 7867 } 7868 7869 if (outNumPoints) *outNumPoints = newNumPoints; 7870 if (outNumIndices) *outNumIndices = newNumIndices; 7871 7872 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7873 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7874 7875 if (!outPoints && !outMat) { 7876 if (offsets) { 7877 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7878 } 7879 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7880 PetscFunctionReturn(PETSC_SUCCESS); 7881 } 7882 7883 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7884 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7885 7886 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7887 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7888 7889 /* output arrays */ 7890 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7891 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7892 7893 // get the new Points 7894 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7895 PetscInt b = points[2 * p]; 7896 PetscInt bDof = 0, bSecDof = 0, bOff; 7897 7898 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7899 if (!bSecDof) continue; 7900 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7901 if (bDof) { 7902 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7903 for (PetscInt q = 0; q < bDof; q++) { 7904 PetscInt a = anchors[bOff + q], aDof = 0; 7905 7906 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7907 if (aDof) { 7908 newPoints[2 * newP] = a; 7909 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7910 newP++; 7911 } 7912 } 7913 } else { 7914 newPoints[2 * newP] = b; 7915 newPoints[2 * newP + 1] = points[2 * p + 1]; 7916 newP++; 7917 } 7918 } 7919 7920 if (outMat) { 7921 PetscScalar *tmpMat; 7922 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7923 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7924 7925 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7926 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7927 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7928 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7929 7930 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7931 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7932 7933 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7934 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7935 7936 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7937 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7938 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7939 // for each field, insert the anchor modification into modMat 7940 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7941 PetscInt fStart = oldOffsets[f]; 7942 PetscInt fNewStart = newOffsets[f]; 7943 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7944 PetscInt b = points[2 * p]; 7945 PetscInt bDof = 0, bSecDof = 0, bOff; 7946 7947 if (b >= sStart && b < sEnd) { 7948 if (numFields) { 7949 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7950 } else { 7951 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7952 } 7953 } 7954 if (!bSecDof) continue; 7955 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7956 if (bDof) { 7957 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7958 for (PetscInt q = 0; q < bDof; q++, newP++) { 7959 PetscInt a = anchors[bOff + q], aDof = 0; 7960 7961 if (a >= sStart && a < sEnd) { 7962 if (numFields) { 7963 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7964 } else { 7965 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7966 } 7967 } 7968 if (aDof) { 7969 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7970 for (PetscInt d = 0; d < bSecDof; d++) { 7971 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7972 } 7973 } 7974 oNew += aDof; 7975 } 7976 } else { 7977 // Insert the identity matrix in this block 7978 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7979 oNew += bSecDof; 7980 newP++; 7981 } 7982 o += bSecDof; 7983 } 7984 } 7985 7986 *outMat = modMat; 7987 7988 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7989 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7990 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7991 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7992 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7993 } 7994 PetscCall(ISRestoreIndices(aIS, &anchors)); 7995 7996 /* output */ 7997 if (outPoints) { 7998 *outPoints = newPoints; 7999 } else { 8000 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 8001 } 8002 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 8003 PetscFunctionReturn(PETSC_SUCCESS); 8004 } 8005 8006 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) 8007 { 8008 PetscScalar *modMat = NULL; 8009 PetscInt newNumIndices = -1; 8010 8011 PetscFunctionBegin; 8012 /* 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. 8013 modMat is that matrix C */ 8014 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 8015 if (outNumIndices) *outNumIndices = newNumIndices; 8016 if (modMat) { 8017 const PetscScalar *newValues = values; 8018 8019 if (multiplyRight) { 8020 PetscScalar *newNewValues = NULL; 8021 PetscBLASInt M, N, K; 8022 PetscScalar a = 1.0, b = 0.0; 8023 8024 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); 8025 8026 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 8027 PetscCall(PetscBLASIntCast(numRows, &N)); 8028 PetscCall(PetscBLASIntCast(numIndices, &K)); 8029 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 8030 // row-major to column-major conversion, right multiplication becomes left multiplication 8031 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 8032 numCols = newNumIndices; 8033 newValues = newNewValues; 8034 } 8035 8036 if (multiplyLeft) { 8037 PetscScalar *newNewValues = NULL; 8038 PetscBLASInt M, N, K; 8039 PetscScalar a = 1.0, b = 0.0; 8040 8041 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); 8042 8043 PetscCall(PetscBLASIntCast(numCols, &M)); 8044 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 8045 PetscCall(PetscBLASIntCast(numIndices, &K)); 8046 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 8047 // row-major to column-major conversion, left multiplication becomes right multiplication 8048 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 8049 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 8050 newValues = newNewValues; 8051 } 8052 *outValues = (PetscScalar *)newValues; 8053 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 8054 } 8055 PetscFunctionReturn(PETSC_SUCCESS); 8056 } 8057 8058 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) 8059 { 8060 PetscFunctionBegin; 8061 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 8062 PetscFunctionReturn(PETSC_SUCCESS); 8063 } 8064 8065 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 8066 { 8067 /* Closure ordering */ 8068 PetscSection clSection; 8069 IS clPoints; 8070 const PetscInt *clp; 8071 PetscInt *points; 8072 PetscInt Ncl, Ni = 0; 8073 8074 PetscFunctionBeginHot; 8075 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8076 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 8077 PetscInt dof; 8078 8079 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8080 Ni += dof; 8081 } 8082 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8083 *closureSize = Ni; 8084 PetscFunctionReturn(PETSC_SUCCESS); 8085 } 8086 8087 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) 8088 { 8089 /* Closure ordering */ 8090 PetscSection clSection; 8091 IS clPoints; 8092 const PetscInt *clp; 8093 PetscInt *points; 8094 const PetscInt *clperm = NULL; 8095 /* Dof permutation and sign flips */ 8096 const PetscInt **perms[32] = {NULL}; 8097 const PetscScalar **flips[32] = {NULL}; 8098 PetscScalar *valCopy = NULL; 8099 /* Hanging node constraints */ 8100 PetscInt *pointsC = NULL; 8101 PetscScalar *valuesC = NULL; 8102 PetscInt NclC, NiC; 8103 8104 PetscInt *idx; 8105 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8106 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8107 PetscInt idxStart, idxEnd; 8108 PetscInt nRows, nCols; 8109 8110 PetscFunctionBeginHot; 8111 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8112 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8113 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8114 PetscAssertPointer(numRows, 6); 8115 PetscAssertPointer(numCols, 7); 8116 if (indices) PetscAssertPointer(indices, 8); 8117 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8118 if (values) PetscAssertPointer(values, 10); 8119 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8120 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8121 PetscCall(PetscArrayzero(offsets, 32)); 8122 /* 1) Get points in closure */ 8123 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8124 if (useClPerm) { 8125 PetscInt depth, clsize; 8126 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8127 for (clsize = 0, p = 0; p < Ncl; p++) { 8128 PetscInt dof; 8129 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8130 clsize += dof; 8131 } 8132 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8133 } 8134 /* 2) Get number of indices on these points and field offsets from section */ 8135 for (p = 0; p < Ncl * 2; p += 2) { 8136 PetscInt dof, fdof; 8137 8138 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8139 for (f = 0; f < Nf; ++f) { 8140 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8141 offsets[f + 1] += fdof; 8142 } 8143 Ni += dof; 8144 } 8145 if (*numRows == -1) *numRows = Ni; 8146 if (*numCols == -1) *numCols = Ni; 8147 nRows = *numRows; 8148 nCols = *numCols; 8149 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8150 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8151 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8152 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8153 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8154 for (f = 0; f < PetscMax(1, Nf); ++f) { 8155 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8156 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8157 /* may need to apply sign changes to the element matrix */ 8158 if (values && flips[f]) { 8159 PetscInt foffset = offsets[f]; 8160 8161 for (p = 0; p < Ncl; ++p) { 8162 PetscInt pnt = points[2 * p], fdof; 8163 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8164 8165 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8166 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8167 if (flip) { 8168 PetscInt i, j, k; 8169 8170 if (!valCopy) { 8171 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8172 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8173 *values = valCopy; 8174 } 8175 for (i = 0; i < fdof; ++i) { 8176 PetscScalar fval = flip[i]; 8177 8178 if (multiplyRight) { 8179 for (k = 0; k < nRows; ++k) valCopy[Ni * k + (foffset + i)] *= fval; 8180 } 8181 if (multiplyLeft) { 8182 for (k = 0; k < nCols; ++k) valCopy[nCols * (foffset + i) + k] *= fval; 8183 } 8184 } 8185 } 8186 foffset += fdof; 8187 } 8188 } 8189 } 8190 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8191 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8192 if (NclC) { 8193 if (multiplyRight) *numCols = NiC; 8194 if (multiplyLeft) *numRows = NiC; 8195 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8196 for (f = 0; f < PetscMax(1, Nf); ++f) { 8197 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8198 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8199 } 8200 for (f = 0; f < PetscMax(1, Nf); ++f) { 8201 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8202 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8203 } 8204 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8205 Ncl = NclC; 8206 Ni = NiC; 8207 points = pointsC; 8208 if (values) *values = valuesC; 8209 } 8210 /* 5) Calculate indices */ 8211 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8212 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8213 if (Nf) { 8214 PetscInt idxOff; 8215 PetscBool useFieldOffsets; 8216 8217 if (outOffsets) { 8218 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8219 } 8220 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8221 if (useFieldOffsets) { 8222 for (p = 0; p < Ncl; ++p) { 8223 const PetscInt pnt = points[p * 2]; 8224 8225 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8226 } 8227 } else { 8228 for (p = 0; p < Ncl; ++p) { 8229 const PetscInt pnt = points[p * 2]; 8230 8231 if (pnt < idxStart || pnt >= idxEnd) continue; 8232 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8233 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8234 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8235 * global section. */ 8236 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8237 } 8238 } 8239 } else { 8240 PetscInt off = 0, idxOff; 8241 8242 for (p = 0; p < Ncl; ++p) { 8243 const PetscInt pnt = points[p * 2]; 8244 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8245 8246 if (pnt < idxStart || pnt >= idxEnd) continue; 8247 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8248 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8249 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8250 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8251 } 8252 } 8253 /* 6) Cleanup */ 8254 for (f = 0; f < PetscMax(1, Nf); ++f) { 8255 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8256 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8257 } 8258 if (NclC) { 8259 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8260 } else { 8261 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8262 } 8263 8264 if (indices) *indices = idx; 8265 PetscFunctionReturn(PETSC_SUCCESS); 8266 } 8267 8268 /*@C 8269 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8270 8271 Not collective 8272 8273 Input Parameters: 8274 + dm - The `DM` 8275 . section - The `PetscSection` describing the points (a local section) 8276 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8277 . point - The point defining the closure 8278 - useClPerm - Use the closure point permutation if available 8279 8280 Output Parameters: 8281 + numIndices - The number of dof indices in the closure of point with the input sections 8282 . indices - The dof indices 8283 . outOffsets - Array, of length the number of fields plus 1, to write the field offsets into, or `NULL` 8284 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8285 8286 Level: advanced 8287 8288 Notes: 8289 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8290 8291 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8292 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8293 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8294 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8295 indices (with the above semantics) are implied. 8296 8297 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8298 `PetscSection`, `DMGetGlobalSection()` 8299 @*/ 8300 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8301 { 8302 PetscInt numRows = -1, numCols = -1; 8303 8304 PetscFunctionBeginHot; 8305 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8306 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8307 *numIndices = numRows; 8308 PetscFunctionReturn(PETSC_SUCCESS); 8309 } 8310 8311 /*@C 8312 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8313 8314 Not collective 8315 8316 Input Parameters: 8317 + dm - The `DM` 8318 . section - The `PetscSection` describing the points (a local section) 8319 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8320 . point - The point defining the closure 8321 - useClPerm - Use the closure point permutation if available 8322 8323 Output Parameters: 8324 + numIndices - The number of dof indices in the closure of point with the input sections 8325 . indices - The dof indices 8326 . outOffsets - Array to write the field offsets into, or `NULL` 8327 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8328 8329 Level: advanced 8330 8331 Notes: 8332 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8333 8334 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8335 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8336 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8337 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8338 indices (with the above semantics) are implied. 8339 8340 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8341 @*/ 8342 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8343 { 8344 PetscFunctionBegin; 8345 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8346 PetscAssertPointer(indices, 7); 8347 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8348 PetscFunctionReturn(PETSC_SUCCESS); 8349 } 8350 8351 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8352 { 8353 DM_Plex *mesh = (DM_Plex *)dm->data; 8354 PetscInt *indices; 8355 PetscInt numIndices; 8356 const PetscScalar *valuesOrig = values; 8357 PetscErrorCode ierr; 8358 8359 PetscFunctionBegin; 8360 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8361 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8362 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8363 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8364 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8365 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8366 8367 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8368 8369 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8370 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8371 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8372 if (ierr) { 8373 PetscMPIInt rank; 8374 8375 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8376 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8377 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8378 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8379 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8380 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8381 } 8382 if (mesh->printFEM > 1) { 8383 PetscInt i; 8384 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8385 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8386 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8387 } 8388 8389 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8390 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8391 PetscFunctionReturn(PETSC_SUCCESS); 8392 } 8393 8394 /*@C 8395 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8396 8397 Not collective 8398 8399 Input Parameters: 8400 + dm - The `DM` 8401 . section - The section describing the layout in `v`, or `NULL` to use the default section 8402 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8403 . A - The matrix 8404 . point - The point in the `DM` 8405 . values - The array of values 8406 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8407 8408 Level: intermediate 8409 8410 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8411 @*/ 8412 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8413 { 8414 PetscFunctionBegin; 8415 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8416 PetscFunctionReturn(PETSC_SUCCESS); 8417 } 8418 8419 /*@C 8420 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8421 8422 Not collective 8423 8424 Input Parameters: 8425 + dmRow - The `DM` for the row fields 8426 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8427 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8428 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8429 . dmCol - The `DM` for the column fields 8430 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8431 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8432 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8433 . A - The matrix 8434 . point - The point in the `DM` 8435 . values - The array of values 8436 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8437 8438 Level: intermediate 8439 8440 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8441 @*/ 8442 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) 8443 { 8444 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8445 PetscInt *indicesRow, *indicesCol; 8446 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8447 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8448 8449 PetscErrorCode ierr; 8450 8451 PetscFunctionBegin; 8452 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8453 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8454 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8455 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8456 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8457 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8458 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8459 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8460 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8461 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8462 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8463 8464 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8465 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8466 valuesV1 = valuesV0; 8467 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8468 valuesV2 = valuesV1; 8469 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8470 8471 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8472 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8473 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8474 if (ierr) { 8475 PetscMPIInt rank; 8476 8477 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8478 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8479 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8480 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8481 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8482 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8483 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8484 } 8485 8486 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8487 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8488 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8489 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8490 PetscFunctionReturn(PETSC_SUCCESS); 8491 } 8492 8493 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8494 { 8495 DM_Plex *mesh = (DM_Plex *)dmf->data; 8496 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8497 PetscInt *cpoints = NULL; 8498 PetscInt *findices, *cindices; 8499 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8500 PetscInt foffsets[32], coffsets[32]; 8501 DMPolytopeType ct; 8502 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8503 PetscErrorCode ierr; 8504 8505 PetscFunctionBegin; 8506 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8507 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8508 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8509 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8510 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8511 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8512 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8513 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8514 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8515 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8516 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8517 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8518 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8519 PetscCall(PetscArrayzero(foffsets, 32)); 8520 PetscCall(PetscArrayzero(coffsets, 32)); 8521 /* Column indices */ 8522 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8523 maxFPoints = numCPoints; 8524 /* Compress out points not in the section */ 8525 /* TODO: Squeeze out points with 0 dof as well */ 8526 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8527 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8528 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8529 cpoints[q * 2] = cpoints[p]; 8530 cpoints[q * 2 + 1] = cpoints[p + 1]; 8531 ++q; 8532 } 8533 } 8534 numCPoints = q; 8535 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8536 PetscInt fdof; 8537 8538 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8539 if (!dof) continue; 8540 for (f = 0; f < numFields; ++f) { 8541 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8542 coffsets[f + 1] += fdof; 8543 } 8544 numCIndices += dof; 8545 } 8546 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8547 /* Row indices */ 8548 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8549 { 8550 DMPlexTransform tr; 8551 DMPolytopeType *rct; 8552 PetscInt *rsize, *rcone, *rornt, Nt; 8553 8554 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8555 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8556 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8557 numSubcells = rsize[Nt - 1]; 8558 PetscCall(DMPlexTransformDestroy(&tr)); 8559 } 8560 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8561 for (r = 0, q = 0; r < numSubcells; ++r) { 8562 /* TODO Map from coarse to fine cells */ 8563 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8564 /* Compress out points not in the section */ 8565 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8566 for (p = 0; p < numFPoints * 2; p += 2) { 8567 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8568 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8569 if (!dof) continue; 8570 for (s = 0; s < q; ++s) 8571 if (fpoints[p] == ftotpoints[s * 2]) break; 8572 if (s < q) continue; 8573 ftotpoints[q * 2] = fpoints[p]; 8574 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8575 ++q; 8576 } 8577 } 8578 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8579 } 8580 numFPoints = q; 8581 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8582 PetscInt fdof; 8583 8584 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8585 if (!dof) continue; 8586 for (f = 0; f < numFields; ++f) { 8587 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8588 foffsets[f + 1] += fdof; 8589 } 8590 numFIndices += dof; 8591 } 8592 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8593 8594 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8595 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8596 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8597 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8598 if (numFields) { 8599 const PetscInt **permsF[32] = {NULL}; 8600 const PetscInt **permsC[32] = {NULL}; 8601 8602 for (f = 0; f < numFields; f++) { 8603 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8604 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8605 } 8606 for (p = 0; p < numFPoints; p++) { 8607 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8608 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8609 } 8610 for (p = 0; p < numCPoints; p++) { 8611 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8612 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8613 } 8614 for (f = 0; f < numFields; f++) { 8615 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8616 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8617 } 8618 } else { 8619 const PetscInt **permsF = NULL; 8620 const PetscInt **permsC = NULL; 8621 8622 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8623 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8624 for (p = 0, off = 0; p < numFPoints; p++) { 8625 const PetscInt *perm = permsF ? permsF[p] : NULL; 8626 8627 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8628 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8629 } 8630 for (p = 0, off = 0; p < numCPoints; p++) { 8631 const PetscInt *perm = permsC ? permsC[p] : NULL; 8632 8633 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8634 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8635 } 8636 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8637 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8638 } 8639 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8640 /* TODO: flips */ 8641 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8642 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8643 if (ierr) { 8644 PetscMPIInt rank; 8645 8646 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8647 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8648 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8649 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8650 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8651 } 8652 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8653 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8654 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8655 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8656 PetscFunctionReturn(PETSC_SUCCESS); 8657 } 8658 8659 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8660 { 8661 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8662 PetscInt *cpoints = NULL; 8663 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8664 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8665 DMPolytopeType ct; 8666 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8667 8668 PetscFunctionBegin; 8669 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8670 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8671 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8672 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8673 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8674 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8675 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8676 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8677 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8678 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8679 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8680 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8681 /* Column indices */ 8682 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8683 maxFPoints = numCPoints; 8684 /* Compress out points not in the section */ 8685 /* TODO: Squeeze out points with 0 dof as well */ 8686 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8687 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8688 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8689 cpoints[q * 2] = cpoints[p]; 8690 cpoints[q * 2 + 1] = cpoints[p + 1]; 8691 ++q; 8692 } 8693 } 8694 numCPoints = q; 8695 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8696 PetscInt fdof; 8697 8698 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8699 if (!dof) continue; 8700 for (f = 0; f < numFields; ++f) { 8701 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8702 coffsets[f + 1] += fdof; 8703 } 8704 numCIndices += dof; 8705 } 8706 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8707 /* Row indices */ 8708 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8709 { 8710 DMPlexTransform tr; 8711 DMPolytopeType *rct; 8712 PetscInt *rsize, *rcone, *rornt, Nt; 8713 8714 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8715 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8716 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8717 numSubcells = rsize[Nt - 1]; 8718 PetscCall(DMPlexTransformDestroy(&tr)); 8719 } 8720 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8721 for (r = 0, q = 0; r < numSubcells; ++r) { 8722 /* TODO Map from coarse to fine cells */ 8723 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8724 /* Compress out points not in the section */ 8725 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8726 for (p = 0; p < numFPoints * 2; p += 2) { 8727 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8728 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8729 if (!dof) continue; 8730 for (s = 0; s < q; ++s) 8731 if (fpoints[p] == ftotpoints[s * 2]) break; 8732 if (s < q) continue; 8733 ftotpoints[q * 2] = fpoints[p]; 8734 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8735 ++q; 8736 } 8737 } 8738 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8739 } 8740 numFPoints = q; 8741 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8742 PetscInt fdof; 8743 8744 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8745 if (!dof) continue; 8746 for (f = 0; f < numFields; ++f) { 8747 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8748 foffsets[f + 1] += fdof; 8749 } 8750 numFIndices += dof; 8751 } 8752 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8753 8754 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8755 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8756 if (numFields) { 8757 const PetscInt **permsF[32] = {NULL}; 8758 const PetscInt **permsC[32] = {NULL}; 8759 8760 for (f = 0; f < numFields; f++) { 8761 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8762 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8763 } 8764 for (p = 0; p < numFPoints; p++) { 8765 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8766 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8767 } 8768 for (p = 0; p < numCPoints; p++) { 8769 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8770 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8771 } 8772 for (f = 0; f < numFields; f++) { 8773 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8774 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8775 } 8776 } else { 8777 const PetscInt **permsF = NULL; 8778 const PetscInt **permsC = NULL; 8779 8780 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8781 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8782 for (p = 0, off = 0; p < numFPoints; p++) { 8783 const PetscInt *perm = permsF ? permsF[p] : NULL; 8784 8785 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8786 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8787 } 8788 for (p = 0, off = 0; p < numCPoints; p++) { 8789 const PetscInt *perm = permsC ? permsC[p] : NULL; 8790 8791 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8792 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8793 } 8794 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8795 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8796 } 8797 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8798 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8799 PetscFunctionReturn(PETSC_SUCCESS); 8800 } 8801 8802 /*@ 8803 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8804 8805 Input Parameter: 8806 . dm - The `DMPLEX` object 8807 8808 Output Parameter: 8809 . cellHeight - The height of a cell 8810 8811 Level: developer 8812 8813 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8814 @*/ 8815 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8816 { 8817 DM_Plex *mesh = (DM_Plex *)dm->data; 8818 8819 PetscFunctionBegin; 8820 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8821 PetscAssertPointer(cellHeight, 2); 8822 *cellHeight = mesh->vtkCellHeight; 8823 PetscFunctionReturn(PETSC_SUCCESS); 8824 } 8825 8826 /*@ 8827 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8828 8829 Input Parameters: 8830 + dm - The `DMPLEX` object 8831 - cellHeight - The height of a cell 8832 8833 Level: developer 8834 8835 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8836 @*/ 8837 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8838 { 8839 DM_Plex *mesh = (DM_Plex *)dm->data; 8840 8841 PetscFunctionBegin; 8842 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8843 mesh->vtkCellHeight = cellHeight; 8844 PetscFunctionReturn(PETSC_SUCCESS); 8845 } 8846 8847 /*@ 8848 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8849 8850 Input Parameters: 8851 + dm - The `DMPLEX` object 8852 - ct - The `DMPolytopeType` of the cell 8853 8854 Output Parameters: 8855 + start - The first cell of this type, or `NULL` 8856 - end - The upper bound on this celltype, or `NULL` 8857 8858 Level: advanced 8859 8860 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8861 @*/ 8862 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end) 8863 { 8864 DM_Plex *mesh = (DM_Plex *)dm->data; 8865 DMLabel label; 8866 PetscInt pStart, pEnd; 8867 8868 PetscFunctionBegin; 8869 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8870 if (start) { 8871 PetscAssertPointer(start, 3); 8872 *start = 0; 8873 } 8874 if (end) { 8875 PetscAssertPointer(end, 4); 8876 *end = 0; 8877 } 8878 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8879 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8880 if (mesh->tr) { 8881 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8882 } else { 8883 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8884 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8885 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8886 } 8887 PetscFunctionReturn(PETSC_SUCCESS); 8888 } 8889 8890 /*@ 8891 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8892 8893 Input Parameters: 8894 + dm - The `DMPLEX` object 8895 - depth - The depth for the given point stratum 8896 8897 Output Parameter: 8898 . gsize - The global number of points in the stratum 8899 8900 Level: advanced 8901 8902 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8903 @*/ 8904 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8905 { 8906 PetscSF sf; 8907 const PetscInt *leaves; 8908 PetscInt Nl, loc, start, end, lsize = 0; 8909 8910 PetscFunctionBegin; 8911 PetscCall(DMGetPointSF(dm, &sf)); 8912 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8913 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8914 for (PetscInt p = start; p < end; ++p) { 8915 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8916 if (loc < 0) ++lsize; 8917 } 8918 PetscCallMPI(MPIU_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8919 PetscFunctionReturn(PETSC_SUCCESS); 8920 } 8921 8922 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8923 { 8924 PetscSection section, globalSection; 8925 PetscInt *numbers, p; 8926 8927 PetscFunctionBegin; 8928 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8929 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8930 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8931 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8932 PetscCall(PetscSectionSetUp(section)); 8933 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8934 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8935 for (p = pStart; p < pEnd; ++p) { 8936 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8937 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8938 else numbers[p - pStart] += shift; 8939 } 8940 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8941 if (globalSize) { 8942 PetscLayout layout; 8943 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8944 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8945 PetscCall(PetscLayoutDestroy(&layout)); 8946 } 8947 PetscCall(PetscSectionDestroy(§ion)); 8948 PetscCall(PetscSectionDestroy(&globalSection)); 8949 PetscFunctionReturn(PETSC_SUCCESS); 8950 } 8951 8952 /*@ 8953 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8954 8955 Input Parameters: 8956 + dm - The `DMPLEX` object 8957 - includeAll - Whether to include all cells, or just the simplex and box cells 8958 8959 Output Parameter: 8960 . globalCellNumbers - Global cell numbers for all cells on this process 8961 8962 Level: developer 8963 8964 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8965 @*/ 8966 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8967 { 8968 PetscInt cellHeight, cStart, cEnd; 8969 8970 PetscFunctionBegin; 8971 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8972 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8973 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8974 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8975 PetscFunctionReturn(PETSC_SUCCESS); 8976 } 8977 8978 /*@ 8979 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8980 8981 Input Parameter: 8982 . dm - The `DMPLEX` object 8983 8984 Output Parameter: 8985 . globalCellNumbers - Global cell numbers for all cells on this process 8986 8987 Level: developer 8988 8989 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8990 @*/ 8991 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8992 { 8993 DM_Plex *mesh = (DM_Plex *)dm->data; 8994 8995 PetscFunctionBegin; 8996 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8997 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8998 *globalCellNumbers = mesh->globalCellNumbers; 8999 PetscFunctionReturn(PETSC_SUCCESS); 9000 } 9001 9002 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 9003 { 9004 PetscInt vStart, vEnd; 9005 9006 PetscFunctionBegin; 9007 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9008 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9009 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 9010 PetscFunctionReturn(PETSC_SUCCESS); 9011 } 9012 9013 /*@ 9014 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 9015 9016 Input Parameter: 9017 . dm - The `DMPLEX` object 9018 9019 Output Parameter: 9020 . globalVertexNumbers - Global vertex numbers for all vertices on this process 9021 9022 Level: developer 9023 9024 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9025 @*/ 9026 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 9027 { 9028 DM_Plex *mesh = (DM_Plex *)dm->data; 9029 9030 PetscFunctionBegin; 9031 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9032 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 9033 *globalVertexNumbers = mesh->globalVertexNumbers; 9034 PetscFunctionReturn(PETSC_SUCCESS); 9035 } 9036 9037 /*@ 9038 DMPlexCreatePointNumbering - Create a global numbering for all points. 9039 9040 Collective 9041 9042 Input Parameter: 9043 . dm - The `DMPLEX` object 9044 9045 Output Parameter: 9046 . globalPointNumbers - Global numbers for all points on this process 9047 9048 Level: developer 9049 9050 Notes: 9051 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 9052 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 9053 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 9054 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 9055 9056 The partitioned mesh is 9057 ``` 9058 (2)--0--(3)--1--(4) (1)--0--(2) 9059 ``` 9060 and its global numbering is 9061 ``` 9062 (3)--0--(4)--1--(5)--2--(6) 9063 ``` 9064 Then the global numbering is provided as 9065 ``` 9066 [0] Number of indices in set 5 9067 [0] 0 0 9068 [0] 1 1 9069 [0] 2 3 9070 [0] 3 4 9071 [0] 4 -6 9072 [1] Number of indices in set 3 9073 [1] 0 2 9074 [1] 1 5 9075 [1] 2 6 9076 ``` 9077 9078 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9079 @*/ 9080 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 9081 { 9082 IS nums[4]; 9083 PetscInt depths[4], gdepths[4], starts[4]; 9084 PetscInt depth, d, shift = 0; 9085 PetscBool empty = PETSC_FALSE; 9086 9087 PetscFunctionBegin; 9088 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9089 PetscCall(DMPlexGetDepth(dm, &depth)); 9090 // For unstratified meshes use dim instead of depth 9091 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9092 // If any stratum is empty, we must mark all empty 9093 for (d = 0; d <= depth; ++d) { 9094 PetscInt end; 9095 9096 depths[d] = depth - d; 9097 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9098 if (!(starts[d] - end)) empty = PETSC_TRUE; 9099 } 9100 if (empty) 9101 for (d = 0; d <= depth; ++d) { 9102 depths[d] = -1; 9103 starts[d] = -1; 9104 } 9105 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9106 PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9107 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]); 9108 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9109 for (d = 0; d <= depth; ++d) { 9110 PetscInt pStart, pEnd, gsize; 9111 9112 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9113 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9114 shift += gsize; 9115 } 9116 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9117 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9118 PetscFunctionReturn(PETSC_SUCCESS); 9119 } 9120 9121 /*@ 9122 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9123 9124 Collective 9125 9126 Input Parameter: 9127 . dm - The `DMPLEX` object 9128 9129 Output Parameter: 9130 . globalEdgeNumbers - Global numbers for all edges on this process 9131 9132 Level: developer 9133 9134 Notes: 9135 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). 9136 9137 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9138 @*/ 9139 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9140 { 9141 PetscSF sf; 9142 PetscInt eStart, eEnd; 9143 9144 PetscFunctionBegin; 9145 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9146 PetscCall(DMGetPointSF(dm, &sf)); 9147 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9148 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9149 PetscFunctionReturn(PETSC_SUCCESS); 9150 } 9151 9152 /*@ 9153 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9154 9155 Input Parameter: 9156 . dm - The `DMPLEX` object 9157 9158 Output Parameter: 9159 . ranks - The rank field 9160 9161 Options Database Key: 9162 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9163 9164 Level: intermediate 9165 9166 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9167 @*/ 9168 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9169 { 9170 DM rdm; 9171 PetscFE fe; 9172 PetscScalar *r; 9173 PetscMPIInt rank; 9174 DMPolytopeType ct; 9175 PetscInt dim, cStart, cEnd, c; 9176 PetscBool simplex; 9177 9178 PetscFunctionBeginUser; 9179 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9180 PetscAssertPointer(ranks, 2); 9181 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9182 PetscCall(DMClone(dm, &rdm)); 9183 PetscCall(DMGetDimension(rdm, &dim)); 9184 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9185 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9186 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9187 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9188 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9189 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9190 PetscCall(PetscFEDestroy(&fe)); 9191 PetscCall(DMCreateDS(rdm)); 9192 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9193 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9194 PetscCall(VecGetArray(*ranks, &r)); 9195 for (c = cStart; c < cEnd; ++c) { 9196 PetscScalar *lr; 9197 9198 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9199 if (lr) *lr = rank; 9200 } 9201 PetscCall(VecRestoreArray(*ranks, &r)); 9202 PetscCall(DMDestroy(&rdm)); 9203 PetscFunctionReturn(PETSC_SUCCESS); 9204 } 9205 9206 /*@ 9207 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9208 9209 Input Parameters: 9210 + dm - The `DMPLEX` 9211 - label - The `DMLabel` 9212 9213 Output Parameter: 9214 . val - The label value field 9215 9216 Options Database Key: 9217 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9218 9219 Level: intermediate 9220 9221 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9222 @*/ 9223 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9224 { 9225 DM rdm, plex; 9226 Vec lval; 9227 PetscSection section; 9228 PetscFE fe; 9229 PetscScalar *v; 9230 PetscInt dim, pStart, pEnd, p, cStart; 9231 DMPolytopeType ct; 9232 char name[PETSC_MAX_PATH_LEN]; 9233 const char *lname, *prefix; 9234 9235 PetscFunctionBeginUser; 9236 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9237 PetscAssertPointer(label, 2); 9238 PetscAssertPointer(val, 3); 9239 PetscCall(DMClone(dm, &rdm)); 9240 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9241 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9242 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9243 PetscCall(DMDestroy(&plex)); 9244 PetscCall(DMGetDimension(rdm, &dim)); 9245 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9246 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9247 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9248 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9249 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9250 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9251 PetscCall(PetscFEDestroy(&fe)); 9252 PetscCall(DMCreateDS(rdm)); 9253 PetscCall(DMCreateGlobalVector(rdm, val)); 9254 PetscCall(DMCreateLocalVector(rdm, &lval)); 9255 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9256 PetscCall(DMGetLocalSection(rdm, §ion)); 9257 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9258 PetscCall(VecGetArray(lval, &v)); 9259 for (p = pStart; p < pEnd; ++p) { 9260 PetscInt cval, dof, off; 9261 9262 PetscCall(PetscSectionGetDof(section, p, &dof)); 9263 if (!dof) continue; 9264 PetscCall(DMLabelGetValue(label, p, &cval)); 9265 PetscCall(PetscSectionGetOffset(section, p, &off)); 9266 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9267 } 9268 PetscCall(VecRestoreArray(lval, &v)); 9269 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9270 PetscCall(VecDestroy(&lval)); 9271 PetscCall(DMDestroy(&rdm)); 9272 PetscFunctionReturn(PETSC_SUCCESS); 9273 } 9274 9275 /*@ 9276 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9277 9278 Input Parameter: 9279 . dm - The `DMPLEX` object 9280 9281 Level: developer 9282 9283 Notes: 9284 This is a useful diagnostic when creating meshes programmatically. 9285 9286 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9287 9288 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9289 @*/ 9290 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9291 { 9292 PetscSection coneSection, supportSection; 9293 const PetscInt *cone, *support; 9294 PetscInt coneSize, c, supportSize, s; 9295 PetscInt pStart, pEnd, p, pp, csize, ssize; 9296 PetscBool storagecheck = PETSC_TRUE; 9297 9298 PetscFunctionBegin; 9299 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9300 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9301 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9302 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9303 /* Check that point p is found in the support of its cone points, and vice versa */ 9304 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9305 for (p = pStart; p < pEnd; ++p) { 9306 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9307 PetscCall(DMPlexGetCone(dm, p, &cone)); 9308 for (c = 0; c < coneSize; ++c) { 9309 PetscBool dup = PETSC_FALSE; 9310 PetscInt d; 9311 for (d = c - 1; d >= 0; --d) { 9312 if (cone[c] == cone[d]) { 9313 dup = PETSC_TRUE; 9314 break; 9315 } 9316 } 9317 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9318 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9319 for (s = 0; s < supportSize; ++s) { 9320 if (support[s] == p) break; 9321 } 9322 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9323 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9324 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9325 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9326 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9327 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9328 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9329 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]); 9330 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9331 } 9332 } 9333 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9334 if (p != pp) { 9335 storagecheck = PETSC_FALSE; 9336 continue; 9337 } 9338 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9339 PetscCall(DMPlexGetSupport(dm, p, &support)); 9340 for (s = 0; s < supportSize; ++s) { 9341 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9342 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9343 for (c = 0; c < coneSize; ++c) { 9344 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9345 if (cone[c] != pp) { 9346 c = 0; 9347 break; 9348 } 9349 if (cone[c] == p) break; 9350 } 9351 if (c >= coneSize) { 9352 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9353 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9354 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9355 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9356 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9357 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9358 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9359 } 9360 } 9361 } 9362 if (storagecheck) { 9363 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9364 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9365 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9366 } 9367 PetscFunctionReturn(PETSC_SUCCESS); 9368 } 9369 9370 /* 9371 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. 9372 */ 9373 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9374 { 9375 DMPolytopeType cct; 9376 PetscInt ptpoints[4]; 9377 const PetscInt *cone, *ccone, *ptcone; 9378 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9379 9380 PetscFunctionBegin; 9381 *unsplit = 0; 9382 switch (ct) { 9383 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9384 ptpoints[npt++] = c; 9385 break; 9386 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9387 PetscCall(DMPlexGetCone(dm, c, &cone)); 9388 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9389 for (cp = 0; cp < coneSize; ++cp) { 9390 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9391 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9392 } 9393 break; 9394 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9395 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9396 PetscCall(DMPlexGetCone(dm, c, &cone)); 9397 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9398 for (cp = 0; cp < coneSize; ++cp) { 9399 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9400 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9401 for (ccp = 0; ccp < cconeSize; ++ccp) { 9402 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9403 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9404 PetscInt p; 9405 for (p = 0; p < npt; ++p) 9406 if (ptpoints[p] == ccone[ccp]) break; 9407 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9408 } 9409 } 9410 } 9411 break; 9412 default: 9413 break; 9414 } 9415 for (pt = 0; pt < npt; ++pt) { 9416 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9417 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9418 } 9419 PetscFunctionReturn(PETSC_SUCCESS); 9420 } 9421 9422 /*@ 9423 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9424 9425 Input Parameters: 9426 + dm - The `DMPLEX` object 9427 - cellHeight - Normally 0 9428 9429 Level: developer 9430 9431 Notes: 9432 This is a useful diagnostic when creating meshes programmatically. 9433 Currently applicable only to homogeneous simplex or tensor meshes. 9434 9435 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9436 9437 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9438 @*/ 9439 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9440 { 9441 DMPlexInterpolatedFlag interp; 9442 DMPolytopeType ct; 9443 PetscInt vStart, vEnd, cStart, cEnd, c; 9444 9445 PetscFunctionBegin; 9446 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9447 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9448 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9449 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9450 for (c = cStart; c < cEnd; ++c) { 9451 PetscInt *closure = NULL; 9452 PetscInt coneSize, closureSize, cl, Nv = 0; 9453 9454 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9455 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9456 if (interp == DMPLEX_INTERPOLATED_FULL) { 9457 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9458 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)); 9459 } 9460 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9461 for (cl = 0; cl < closureSize * 2; cl += 2) { 9462 const PetscInt p = closure[cl]; 9463 if ((p >= vStart) && (p < vEnd)) ++Nv; 9464 } 9465 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9466 /* Special Case: Tensor faces with identified vertices */ 9467 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9468 PetscInt unsplit; 9469 9470 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9471 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9472 } 9473 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)); 9474 } 9475 PetscFunctionReturn(PETSC_SUCCESS); 9476 } 9477 9478 /*@ 9479 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9480 9481 Collective 9482 9483 Input Parameters: 9484 + dm - The `DMPLEX` object 9485 - cellHeight - Normally 0 9486 9487 Level: developer 9488 9489 Notes: 9490 This is a useful diagnostic when creating meshes programmatically. 9491 This routine is only relevant for meshes that are fully interpolated across all ranks. 9492 It will error out if a partially interpolated mesh is given on some rank. 9493 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9494 9495 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9496 9497 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9498 @*/ 9499 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9500 { 9501 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9502 DMPlexInterpolatedFlag interpEnum; 9503 9504 PetscFunctionBegin; 9505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9506 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9507 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9508 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9509 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9510 PetscFunctionReturn(PETSC_SUCCESS); 9511 } 9512 9513 PetscCall(DMGetDimension(dm, &dim)); 9514 PetscCall(DMPlexGetDepth(dm, &depth)); 9515 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9516 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9517 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9518 for (c = cStart; c < cEnd; ++c) { 9519 const PetscInt *cone, *ornt, *faceSizes, *faces; 9520 const DMPolytopeType *faceTypes; 9521 DMPolytopeType ct; 9522 PetscInt numFaces, coneSize, f; 9523 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9524 9525 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9526 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9527 if (unsplit) continue; 9528 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9529 PetscCall(DMPlexGetCone(dm, c, &cone)); 9530 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9531 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9532 for (cl = 0; cl < closureSize * 2; cl += 2) { 9533 const PetscInt p = closure[cl]; 9534 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9535 } 9536 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9537 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); 9538 for (f = 0; f < numFaces; ++f) { 9539 DMPolytopeType fct; 9540 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9541 9542 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9543 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9544 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9545 const PetscInt p = fclosure[cl]; 9546 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9547 } 9548 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]); 9549 for (v = 0; v < fnumCorners; ++v) { 9550 if (fclosure[v] != faces[fOff + v]) { 9551 PetscInt v1; 9552 9553 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9554 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9555 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9556 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9557 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9558 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]); 9559 } 9560 } 9561 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9562 fOff += faceSizes[f]; 9563 } 9564 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9565 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9566 } 9567 } 9568 PetscFunctionReturn(PETSC_SUCCESS); 9569 } 9570 9571 /*@ 9572 DMPlexCheckGeometry - Check the geometry of mesh cells 9573 9574 Input Parameter: 9575 . dm - The `DMPLEX` object 9576 9577 Level: developer 9578 9579 Notes: 9580 This is a useful diagnostic when creating meshes programmatically. 9581 9582 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9583 9584 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9585 @*/ 9586 PetscErrorCode DMPlexCheckGeometry(DM dm) 9587 { 9588 Vec coordinates; 9589 PetscReal detJ, J[9], refVol = 1.0; 9590 PetscReal vol; 9591 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9592 9593 PetscFunctionBegin; 9594 PetscCall(DMGetDimension(dm, &dim)); 9595 PetscCall(DMGetCoordinateDim(dm, &dE)); 9596 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9597 PetscCall(DMPlexGetDepth(dm, &depth)); 9598 for (d = 0; d < dim; ++d) refVol *= 2.0; 9599 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9600 /* Make sure local coordinates are created, because that step is collective */ 9601 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9602 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9603 for (c = cStart; c < cEnd; ++c) { 9604 DMPolytopeType ct; 9605 PetscInt unsplit; 9606 PetscBool ignoreZeroVol = PETSC_FALSE; 9607 9608 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9609 switch (ct) { 9610 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9611 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9612 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9613 ignoreZeroVol = PETSC_TRUE; 9614 break; 9615 default: 9616 break; 9617 } 9618 switch (ct) { 9619 case DM_POLYTOPE_TRI_PRISM: 9620 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9621 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9622 case DM_POLYTOPE_PYRAMID: 9623 continue; 9624 default: 9625 break; 9626 } 9627 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9628 if (unsplit) continue; 9629 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9630 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); 9631 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9632 /* This should work with periodicity since DG coordinates should be used */ 9633 if (depth > 1) { 9634 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9635 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); 9636 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9637 } 9638 } 9639 PetscFunctionReturn(PETSC_SUCCESS); 9640 } 9641 9642 /*@ 9643 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9644 9645 Collective 9646 9647 Input Parameters: 9648 + dm - The `DMPLEX` object 9649 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9650 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9651 9652 Level: developer 9653 9654 Notes: 9655 This is mainly intended for debugging/testing purposes. 9656 9657 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9658 9659 Extra roots can come from periodic cuts, where additional points appear on the boundary 9660 9661 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9662 @*/ 9663 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9664 { 9665 PetscInt l, nleaves, nroots, overlap; 9666 const PetscInt *locals; 9667 const PetscSFNode *remotes; 9668 PetscBool distributed; 9669 MPI_Comm comm; 9670 PetscMPIInt rank; 9671 9672 PetscFunctionBegin; 9673 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9674 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9675 else pointSF = dm->sf; 9676 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9677 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9678 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9679 { 9680 PetscMPIInt mpiFlag; 9681 9682 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9683 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9684 } 9685 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9686 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9687 if (!distributed) { 9688 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); 9689 PetscFunctionReturn(PETSC_SUCCESS); 9690 } 9691 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); 9692 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9693 9694 /* Check SF graph is compatible with DMPlex chart */ 9695 { 9696 PetscInt pStart, pEnd, maxLeaf; 9697 9698 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9699 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9700 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9701 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9702 } 9703 9704 /* Check there are no cells in interface */ 9705 if (!overlap) { 9706 PetscInt cellHeight, cStart, cEnd; 9707 9708 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9709 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9710 for (l = 0; l < nleaves; ++l) { 9711 const PetscInt point = locals ? locals[l] : l; 9712 9713 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9714 } 9715 } 9716 9717 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9718 { 9719 const PetscInt *rootdegree; 9720 9721 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9722 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9723 for (l = 0; l < nleaves; ++l) { 9724 const PetscInt point = locals ? locals[l] : l; 9725 const PetscInt *cone; 9726 PetscInt coneSize, c, idx; 9727 9728 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9729 PetscCall(DMPlexGetCone(dm, point, &cone)); 9730 for (c = 0; c < coneSize; ++c) { 9731 if (!rootdegree[cone[c]]) { 9732 if (locals) { 9733 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9734 } else { 9735 idx = (cone[c] < nleaves) ? cone[c] : -1; 9736 } 9737 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9738 } 9739 } 9740 } 9741 } 9742 PetscFunctionReturn(PETSC_SUCCESS); 9743 } 9744 9745 /*@ 9746 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9747 9748 Collective 9749 9750 Input Parameter: 9751 . dm - The `DMPLEX` object 9752 9753 Level: developer 9754 9755 Notes: 9756 This is mainly intended for debugging/testing purposes. 9757 9758 Other cell types which are disconnected would be caught by the symmetry and face checks. 9759 9760 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9761 9762 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9763 @*/ 9764 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9765 { 9766 PetscInt pStart, pEnd, vStart, vEnd; 9767 9768 PetscFunctionBegin; 9769 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9770 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9771 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9772 for (PetscInt v = vStart; v < vEnd; ++v) { 9773 PetscInt suppSize; 9774 9775 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9776 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9777 } 9778 PetscFunctionReturn(PETSC_SUCCESS); 9779 } 9780 9781 /*@ 9782 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9783 9784 Input Parameter: 9785 . dm - The `DMPLEX` object 9786 9787 Level: developer 9788 9789 Notes: 9790 This is a useful diagnostic when creating meshes programmatically. 9791 9792 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9793 9794 Currently does not include `DMPlexCheckCellShape()`. 9795 9796 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9797 @*/ 9798 PetscErrorCode DMPlexCheck(DM dm) 9799 { 9800 PetscInt cellHeight; 9801 9802 PetscFunctionBegin; 9803 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9804 PetscCall(DMPlexCheckSymmetry(dm)); 9805 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9806 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9807 PetscCall(DMPlexCheckGeometry(dm)); 9808 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9809 PetscCall(DMPlexCheckInterfaceCones(dm)); 9810 PetscCall(DMPlexCheckOrphanVertices(dm)); 9811 PetscFunctionReturn(PETSC_SUCCESS); 9812 } 9813 9814 typedef struct cell_stats { 9815 PetscReal min, max, sum, squaresum; 9816 PetscInt count; 9817 } cell_stats_t; 9818 9819 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9820 { 9821 PetscInt i, N = *len; 9822 9823 for (i = 0; i < N; i++) { 9824 cell_stats_t *A = (cell_stats_t *)a; 9825 cell_stats_t *B = (cell_stats_t *)b; 9826 9827 B->min = PetscMin(A->min, B->min); 9828 B->max = PetscMax(A->max, B->max); 9829 B->sum += A->sum; 9830 B->squaresum += A->squaresum; 9831 B->count += A->count; 9832 } 9833 } 9834 9835 /*@ 9836 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9837 9838 Collective 9839 9840 Input Parameters: 9841 + dm - The `DMPLEX` object 9842 . output - If true, statistics will be displayed on `stdout` 9843 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9844 9845 Level: developer 9846 9847 Notes: 9848 This is mainly intended for debugging/testing purposes. 9849 9850 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9851 9852 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9853 @*/ 9854 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9855 { 9856 DM dmCoarse; 9857 cell_stats_t stats, globalStats; 9858 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9859 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9860 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9861 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9862 PetscMPIInt rank, size; 9863 9864 PetscFunctionBegin; 9865 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9866 stats.min = PETSC_MAX_REAL; 9867 stats.max = PETSC_MIN_REAL; 9868 stats.sum = stats.squaresum = 0.; 9869 stats.count = 0; 9870 9871 PetscCallMPI(MPI_Comm_size(comm, &size)); 9872 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9873 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9874 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9875 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9876 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9877 for (c = cStart; c < cEnd; c++) { 9878 PetscInt i; 9879 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9880 9881 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9882 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9883 for (i = 0; i < PetscSqr(cdim); ++i) { 9884 frobJ += J[i] * J[i]; 9885 frobInvJ += invJ[i] * invJ[i]; 9886 } 9887 cond2 = frobJ * frobInvJ; 9888 cond = PetscSqrtReal(cond2); 9889 9890 stats.min = PetscMin(stats.min, cond); 9891 stats.max = PetscMax(stats.max, cond); 9892 stats.sum += cond; 9893 stats.squaresum += cond2; 9894 stats.count++; 9895 if (output && cond > limit) { 9896 PetscSection coordSection; 9897 Vec coordsLocal; 9898 PetscScalar *coords = NULL; 9899 PetscInt Nv, d, clSize, cl, *closure = NULL; 9900 9901 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9902 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9903 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9904 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9905 for (i = 0; i < Nv / cdim; ++i) { 9906 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9907 for (d = 0; d < cdim; ++d) { 9908 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9909 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9910 } 9911 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9912 } 9913 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9914 for (cl = 0; cl < clSize * 2; cl += 2) { 9915 const PetscInt edge = closure[cl]; 9916 9917 if ((edge >= eStart) && (edge < eEnd)) { 9918 PetscReal len; 9919 9920 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9921 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9922 } 9923 } 9924 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9925 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9926 } 9927 } 9928 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9929 9930 if (size > 1) { 9931 PetscMPIInt blockLengths[2] = {4, 1}; 9932 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9933 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9934 MPI_Op statReduce; 9935 9936 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9937 PetscCallMPI(MPI_Type_commit(&statType)); 9938 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9939 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9940 PetscCallMPI(MPI_Op_free(&statReduce)); 9941 PetscCallMPI(MPI_Type_free(&statType)); 9942 } else { 9943 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9944 } 9945 if (rank == 0) { 9946 count = globalStats.count; 9947 min = globalStats.min; 9948 max = globalStats.max; 9949 mean = globalStats.sum / globalStats.count; 9950 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9951 } 9952 9953 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)); 9954 PetscCall(PetscFree2(J, invJ)); 9955 9956 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9957 if (dmCoarse) { 9958 PetscBool isplex; 9959 9960 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9961 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9962 } 9963 PetscFunctionReturn(PETSC_SUCCESS); 9964 } 9965 9966 /*@ 9967 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9968 orthogonal quality below given tolerance. 9969 9970 Collective 9971 9972 Input Parameters: 9973 + dm - The `DMPLEX` object 9974 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9975 - atol - [0, 1] Absolute tolerance for tagging cells. 9976 9977 Output Parameters: 9978 + OrthQual - `Vec` containing orthogonal quality per cell 9979 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9980 9981 Options Database Keys: 9982 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9983 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9984 9985 Level: intermediate 9986 9987 Notes: 9988 Orthogonal quality is given by the following formula\: 9989 9990 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9991 9992 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 9993 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9994 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9995 calculating the cosine of the angle between these vectors. 9996 9997 Orthogonal quality ranges from 1 (best) to 0 (worst). 9998 9999 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 10000 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 10001 10002 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 10003 10004 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 10005 @*/ 10006 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 10007 { 10008 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 10009 PetscInt *idx; 10010 PetscScalar *oqVals; 10011 const PetscScalar *cellGeomArr, *faceGeomArr; 10012 PetscReal *ci, *fi, *Ai; 10013 MPI_Comm comm; 10014 Vec cellgeom, facegeom; 10015 DM dmFace, dmCell; 10016 IS glob; 10017 ISLocalToGlobalMapping ltog; 10018 PetscViewer vwr; 10019 10020 PetscFunctionBegin; 10021 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10022 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 10023 PetscAssertPointer(OrthQual, 4); 10024 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 10025 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 10026 PetscCall(DMGetDimension(dm, &nc)); 10027 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 10028 { 10029 DMPlexInterpolatedFlag interpFlag; 10030 10031 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 10032 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 10033 PetscMPIInt rank; 10034 10035 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 10036 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 10037 } 10038 } 10039 if (OrthQualLabel) { 10040 PetscAssertPointer(OrthQualLabel, 5); 10041 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 10042 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 10043 } else { 10044 *OrthQualLabel = NULL; 10045 } 10046 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 10047 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 10048 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 10049 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 10050 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 10051 PetscCall(VecCreate(comm, OrthQual)); 10052 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 10053 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 10054 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 10055 PetscCall(VecSetUp(*OrthQual)); 10056 PetscCall(ISDestroy(&glob)); 10057 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 10058 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 10059 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 10060 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 10061 PetscCall(VecGetDM(cellgeom, &dmCell)); 10062 PetscCall(VecGetDM(facegeom, &dmFace)); 10063 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 10064 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 10065 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 10066 PetscInt cellarr[2], *adj = NULL; 10067 PetscScalar *cArr, *fArr; 10068 PetscReal minvalc = 1.0, minvalf = 1.0; 10069 PetscFVCellGeom *cg; 10070 10071 idx[cellIter] = cell - cStart; 10072 cellarr[0] = cell; 10073 /* Make indexing into cellGeom easier */ 10074 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10075 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10076 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10077 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10078 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10079 PetscInt i; 10080 const PetscInt neigh = adj[cellneigh]; 10081 PetscReal normci = 0, normfi = 0, normai = 0; 10082 PetscFVCellGeom *cgneigh; 10083 PetscFVFaceGeom *fg; 10084 10085 /* Don't count ourselves in the neighbor list */ 10086 if (neigh == cell) continue; 10087 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10088 cellarr[1] = neigh; 10089 { 10090 PetscInt numcovpts; 10091 const PetscInt *covpts; 10092 10093 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10094 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10095 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10096 } 10097 10098 /* Compute c_i, f_i and their norms */ 10099 for (i = 0; i < nc; i++) { 10100 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10101 fi[i] = fg->centroid[i] - cg->centroid[i]; 10102 Ai[i] = fg->normal[i]; 10103 normci += PetscPowReal(ci[i], 2); 10104 normfi += PetscPowReal(fi[i], 2); 10105 normai += PetscPowReal(Ai[i], 2); 10106 } 10107 normci = PetscSqrtReal(normci); 10108 normfi = PetscSqrtReal(normfi); 10109 normai = PetscSqrtReal(normai); 10110 10111 /* Normalize and compute for each face-cell-normal pair */ 10112 for (i = 0; i < nc; i++) { 10113 ci[i] = ci[i] / normci; 10114 fi[i] = fi[i] / normfi; 10115 Ai[i] = Ai[i] / normai; 10116 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10117 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10118 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10119 } 10120 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10121 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10122 } 10123 PetscCall(PetscFree(adj)); 10124 PetscCall(PetscFree2(cArr, fArr)); 10125 /* Defer to cell if they're equal */ 10126 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10127 if (OrthQualLabel) { 10128 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10129 } 10130 } 10131 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10132 PetscCall(VecAssemblyBegin(*OrthQual)); 10133 PetscCall(VecAssemblyEnd(*OrthQual)); 10134 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10135 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10136 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10137 if (OrthQualLabel) { 10138 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10139 } 10140 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10141 PetscCall(PetscViewerDestroy(&vwr)); 10142 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10143 PetscFunctionReturn(PETSC_SUCCESS); 10144 } 10145 10146 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10147 * interpolator construction */ 10148 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10149 { 10150 PetscSection section, newSection, gsection; 10151 PetscSF sf; 10152 PetscBool hasConstraints, ghasConstraints; 10153 10154 PetscFunctionBegin; 10155 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10156 PetscAssertPointer(odm, 2); 10157 PetscCall(DMGetLocalSection(dm, §ion)); 10158 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10159 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10160 if (!ghasConstraints) { 10161 PetscCall(PetscObjectReference((PetscObject)dm)); 10162 *odm = dm; 10163 PetscFunctionReturn(PETSC_SUCCESS); 10164 } 10165 PetscCall(DMClone(dm, odm)); 10166 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10167 PetscCall(DMGetLocalSection(*odm, &newSection)); 10168 PetscCall(DMGetPointSF(*odm, &sf)); 10169 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10170 PetscCall(DMSetGlobalSection(*odm, gsection)); 10171 PetscCall(PetscSectionDestroy(&gsection)); 10172 PetscFunctionReturn(PETSC_SUCCESS); 10173 } 10174 10175 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10176 { 10177 DM dmco, dmfo; 10178 Mat interpo; 10179 Vec rscale; 10180 Vec cglobalo, clocal; 10181 Vec fglobal, fglobalo, flocal; 10182 PetscBool regular; 10183 10184 PetscFunctionBegin; 10185 PetscCall(DMGetFullDM(dmc, &dmco)); 10186 PetscCall(DMGetFullDM(dmf, &dmfo)); 10187 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10188 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10189 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10190 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10191 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10192 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10193 PetscCall(VecSet(cglobalo, 0.)); 10194 PetscCall(VecSet(clocal, 0.)); 10195 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10196 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10197 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10198 PetscCall(VecSet(fglobal, 0.)); 10199 PetscCall(VecSet(fglobalo, 0.)); 10200 PetscCall(VecSet(flocal, 0.)); 10201 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10202 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10203 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10204 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10205 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10206 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10207 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10208 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10209 *shift = fglobal; 10210 PetscCall(VecDestroy(&flocal)); 10211 PetscCall(VecDestroy(&fglobalo)); 10212 PetscCall(VecDestroy(&clocal)); 10213 PetscCall(VecDestroy(&cglobalo)); 10214 PetscCall(VecDestroy(&rscale)); 10215 PetscCall(MatDestroy(&interpo)); 10216 PetscCall(DMDestroy(&dmfo)); 10217 PetscCall(DMDestroy(&dmco)); 10218 PetscFunctionReturn(PETSC_SUCCESS); 10219 } 10220 10221 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10222 { 10223 PetscObject shifto; 10224 Vec shift; 10225 10226 PetscFunctionBegin; 10227 if (!interp) { 10228 Vec rscale; 10229 10230 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10231 PetscCall(VecDestroy(&rscale)); 10232 } else { 10233 PetscCall(PetscObjectReference((PetscObject)interp)); 10234 } 10235 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10236 if (!shifto) { 10237 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10238 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10239 shifto = (PetscObject)shift; 10240 PetscCall(VecDestroy(&shift)); 10241 } 10242 shift = (Vec)shifto; 10243 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10244 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10245 PetscCall(MatDestroy(&interp)); 10246 PetscFunctionReturn(PETSC_SUCCESS); 10247 } 10248 10249 /* Pointwise interpolation 10250 Just code FEM for now 10251 u^f = I u^c 10252 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10253 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10254 I_{ij} = psi^f_i phi^c_j 10255 */ 10256 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10257 { 10258 PetscSection gsc, gsf; 10259 PetscInt m, n; 10260 void *ctx; 10261 DM cdm; 10262 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10263 10264 PetscFunctionBegin; 10265 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10266 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10267 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10268 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10269 10270 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10271 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10272 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10273 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10274 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10275 10276 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10277 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10278 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10279 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10280 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10281 if (scaling) { 10282 /* Use naive scaling */ 10283 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10284 } 10285 PetscFunctionReturn(PETSC_SUCCESS); 10286 } 10287 10288 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10289 { 10290 VecScatter ctx; 10291 10292 PetscFunctionBegin; 10293 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10294 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10295 PetscCall(VecScatterDestroy(&ctx)); 10296 PetscFunctionReturn(PETSC_SUCCESS); 10297 } 10298 10299 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[]) 10300 { 10301 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10302 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10303 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10304 } 10305 10306 // The assumption here is that the test field is a vector and the basis field is a scalar (so we need the gradient) 10307 static void g1_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]) 10308 { 10309 for (PetscInt c = 0; c < dim; ++c) g1[c * dim + c] = 1.0; 10310 } 10311 10312 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10313 { 10314 DM dmc; 10315 PetscDS ds; 10316 Vec ones, locmass; 10317 IS cellIS; 10318 PetscFormKey key; 10319 PetscInt depth; 10320 10321 PetscFunctionBegin; 10322 PetscCall(DMClone(dm, &dmc)); 10323 PetscCall(DMCopyDisc(dm, dmc)); 10324 PetscCall(DMGetDS(dmc, &ds)); 10325 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10326 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10327 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10328 else PetscCall(DMGetLocalVector(dm, &locmass)); 10329 PetscCall(DMGetLocalVector(dm, &ones)); 10330 PetscCall(DMPlexGetDepth(dm, &depth)); 10331 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10332 PetscCall(VecSet(locmass, 0.0)); 10333 PetscCall(VecSet(ones, 1.0)); 10334 key.label = NULL; 10335 key.value = 0; 10336 key.field = 0; 10337 key.part = 0; 10338 PetscCall(DMPlexComputeJacobianActionByKey(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10339 PetscCall(ISDestroy(&cellIS)); 10340 if (mass) { 10341 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10342 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10343 } 10344 PetscCall(DMRestoreLocalVector(dm, &ones)); 10345 if (lmass) *lmass = locmass; 10346 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10347 PetscCall(DMDestroy(&dmc)); 10348 PetscFunctionReturn(PETSC_SUCCESS); 10349 } 10350 10351 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10352 { 10353 PetscSection gsc, gsf; 10354 PetscInt m, n; 10355 void *ctx; 10356 DM cdm; 10357 PetscBool regular; 10358 10359 PetscFunctionBegin; 10360 if (dmFine == dmCoarse) { 10361 DM dmc; 10362 PetscDS ds; 10363 PetscWeakForm wf; 10364 Vec u; 10365 IS cellIS; 10366 PetscFormKey key; 10367 PetscInt depth; 10368 10369 PetscCall(DMClone(dmFine, &dmc)); 10370 PetscCall(DMCopyDisc(dmFine, dmc)); 10371 PetscCall(DMGetDS(dmc, &ds)); 10372 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10373 PetscCall(PetscWeakFormClear(wf)); 10374 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10375 PetscCall(DMCreateMatrix(dmc, mass)); 10376 PetscCall(DMGetLocalVector(dmc, &u)); 10377 PetscCall(DMPlexGetDepth(dmc, &depth)); 10378 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10379 PetscCall(MatZeroEntries(*mass)); 10380 key.label = NULL; 10381 key.value = 0; 10382 key.field = 0; 10383 key.part = 0; 10384 PetscCall(DMPlexComputeJacobianByKey(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10385 PetscCall(ISDestroy(&cellIS)); 10386 PetscCall(DMRestoreLocalVector(dmc, &u)); 10387 PetscCall(DMDestroy(&dmc)); 10388 } else { 10389 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10390 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10391 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10392 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10393 10394 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10395 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10396 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10397 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10398 10399 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10400 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10401 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10402 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10403 } 10404 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10405 PetscFunctionReturn(PETSC_SUCCESS); 10406 } 10407 10408 PetscErrorCode DMCreateGradientMatrix_Plex(DM dmc, DM dmr, Mat *derv) 10409 { 10410 PetscSection gsc, gsf; 10411 PetscInt m, n; 10412 void *ctx; 10413 10414 PetscFunctionBegin; 10415 PetscCall(DMGetGlobalSection(dmr, &gsf)); 10416 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10417 PetscCall(DMGetGlobalSection(dmc, &gsc)); 10418 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10419 10420 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmc), derv)); 10421 PetscCall(PetscObjectSetName((PetscObject)*derv, "Plex Derivative Matrix")); 10422 PetscCall(MatSetSizes(*derv, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10423 PetscCall(MatSetType(*derv, dmc->mattype)); 10424 10425 PetscCall(DMGetApplicationContext(dmr, &ctx)); 10426 { 10427 DM ndmr; 10428 PetscDS ds; 10429 PetscWeakForm wf; 10430 Vec u; 10431 IS cellIS; 10432 PetscFormKey key; 10433 PetscInt depth, Nf; 10434 10435 PetscCall(DMClone(dmr, &ndmr)); 10436 PetscCall(DMCopyDisc(dmr, ndmr)); 10437 PetscCall(DMGetDS(ndmr, &ds)); 10438 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10439 PetscCall(PetscWeakFormClear(wf)); 10440 PetscCall(PetscDSGetNumFields(ds, &Nf)); 10441 for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, NULL, g1_identity_private, NULL, NULL)); 10442 PetscCall(DMGetLocalVector(ndmr, &u)); 10443 PetscCall(DMPlexGetDepth(ndmr, &depth)); 10444 PetscCall(DMGetStratumIS(ndmr, "depth", depth, &cellIS)); 10445 PetscCall(MatZeroEntries(*derv)); 10446 key.label = NULL; 10447 key.value = 0; 10448 key.field = 0; 10449 key.part = 0; 10450 PetscCall(DMPlexComputeJacobianByKeyGeneral(ndmr, dmc, key, cellIS, 0.0, 0.0, u, NULL, *derv, *derv, NULL)); 10451 PetscCall(ISDestroy(&cellIS)); 10452 PetscCall(DMRestoreLocalVector(ndmr, &u)); 10453 PetscCall(DMDestroy(&ndmr)); 10454 } 10455 PetscCall(MatViewFromOptions(*derv, NULL, "-gradient_mat_view")); 10456 PetscFunctionReturn(PETSC_SUCCESS); 10457 } 10458 10459 /*@ 10460 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10461 10462 Input Parameter: 10463 . dm - The `DMPLEX` object 10464 10465 Output Parameter: 10466 . regular - The flag 10467 10468 Level: intermediate 10469 10470 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10471 @*/ 10472 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10473 { 10474 PetscFunctionBegin; 10475 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10476 PetscAssertPointer(regular, 2); 10477 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10478 PetscFunctionReturn(PETSC_SUCCESS); 10479 } 10480 10481 /*@ 10482 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10483 10484 Input Parameters: 10485 + dm - The `DMPLEX` object 10486 - regular - The flag 10487 10488 Level: intermediate 10489 10490 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10491 @*/ 10492 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10493 { 10494 PetscFunctionBegin; 10495 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10496 ((DM_Plex *)dm->data)->regularRefinement = regular; 10497 PetscFunctionReturn(PETSC_SUCCESS); 10498 } 10499 10500 /*@ 10501 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10502 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10503 10504 Not Collective 10505 10506 Input Parameter: 10507 . dm - The `DMPLEX` object 10508 10509 Output Parameters: 10510 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10511 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10512 10513 Level: intermediate 10514 10515 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10516 @*/ 10517 PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS) 10518 { 10519 DM_Plex *plex = (DM_Plex *)dm->data; 10520 10521 PetscFunctionBegin; 10522 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10523 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10524 if (anchorSection) *anchorSection = plex->anchorSection; 10525 if (anchorIS) *anchorIS = plex->anchorIS; 10526 PetscFunctionReturn(PETSC_SUCCESS); 10527 } 10528 10529 /*@ 10530 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10531 10532 Collective 10533 10534 Input Parameters: 10535 + dm - The `DMPLEX` object 10536 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10537 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10538 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10539 10540 Level: intermediate 10541 10542 Notes: 10543 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10544 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10545 combination of other points' degrees of freedom. 10546 10547 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10548 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10549 10550 The reference counts of `anchorSection` and `anchorIS` are incremented. 10551 10552 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10553 @*/ 10554 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10555 { 10556 DM_Plex *plex = (DM_Plex *)dm->data; 10557 PetscMPIInt result; 10558 10559 PetscFunctionBegin; 10560 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10561 if (anchorSection) { 10562 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10563 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10564 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10565 } 10566 if (anchorIS) { 10567 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10568 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10569 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10570 } 10571 10572 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10573 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10574 plex->anchorSection = anchorSection; 10575 10576 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10577 PetscCall(ISDestroy(&plex->anchorIS)); 10578 plex->anchorIS = anchorIS; 10579 10580 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10581 PetscInt size, a, pStart, pEnd; 10582 const PetscInt *anchors; 10583 10584 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10585 PetscCall(ISGetLocalSize(anchorIS, &size)); 10586 PetscCall(ISGetIndices(anchorIS, &anchors)); 10587 for (a = 0; a < size; a++) { 10588 PetscInt p; 10589 10590 p = anchors[a]; 10591 if (p >= pStart && p < pEnd) { 10592 PetscInt dof; 10593 10594 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10595 if (dof) { 10596 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10597 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10598 } 10599 } 10600 } 10601 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10602 } 10603 /* reset the generic constraints */ 10604 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10605 PetscFunctionReturn(PETSC_SUCCESS); 10606 } 10607 10608 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10609 { 10610 PetscSection anchorSection; 10611 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10612 10613 PetscFunctionBegin; 10614 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10615 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10616 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10617 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10618 if (numFields) { 10619 PetscInt f; 10620 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10621 10622 for (f = 0; f < numFields; f++) { 10623 PetscInt numComp; 10624 10625 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10626 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10627 } 10628 } 10629 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10630 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10631 pStart = PetscMax(pStart, sStart); 10632 pEnd = PetscMin(pEnd, sEnd); 10633 pEnd = PetscMax(pStart, pEnd); 10634 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10635 for (p = pStart; p < pEnd; p++) { 10636 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10637 if (dof) { 10638 PetscCall(PetscSectionGetDof(section, p, &dof)); 10639 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10640 for (f = 0; f < numFields; f++) { 10641 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10642 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10643 } 10644 } 10645 } 10646 PetscCall(PetscSectionSetUp(*cSec)); 10647 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10648 PetscFunctionReturn(PETSC_SUCCESS); 10649 } 10650 10651 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10652 { 10653 PetscSection aSec; 10654 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10655 const PetscInt *anchors; 10656 PetscInt numFields, f; 10657 IS aIS; 10658 MatType mtype; 10659 PetscBool iscuda, iskokkos; 10660 10661 PetscFunctionBegin; 10662 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10663 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10664 PetscCall(PetscSectionGetStorageSize(section, &n)); 10665 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10666 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10667 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10668 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10669 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10670 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10671 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10672 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10673 else mtype = MATSEQAIJ; 10674 PetscCall(MatSetType(*cMat, mtype)); 10675 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10676 PetscCall(ISGetIndices(aIS, &anchors)); 10677 /* cSec will be a subset of aSec and section */ 10678 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10679 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10680 PetscCall(PetscMalloc1(m + 1, &i)); 10681 i[0] = 0; 10682 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10683 for (p = pStart; p < pEnd; p++) { 10684 PetscInt rDof, rOff, r; 10685 10686 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10687 if (!rDof) continue; 10688 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10689 if (numFields) { 10690 for (f = 0; f < numFields; f++) { 10691 annz = 0; 10692 for (r = 0; r < rDof; r++) { 10693 a = anchors[rOff + r]; 10694 if (a < sStart || a >= sEnd) continue; 10695 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10696 annz += aDof; 10697 } 10698 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10699 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10700 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10701 } 10702 } else { 10703 annz = 0; 10704 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10705 for (q = 0; q < dof; q++) { 10706 a = anchors[rOff + q]; 10707 if (a < sStart || a >= sEnd) continue; 10708 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10709 annz += aDof; 10710 } 10711 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10712 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10713 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10714 } 10715 } 10716 nnz = i[m]; 10717 PetscCall(PetscMalloc1(nnz, &j)); 10718 offset = 0; 10719 for (p = pStart; p < pEnd; p++) { 10720 if (numFields) { 10721 for (f = 0; f < numFields; f++) { 10722 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10723 for (q = 0; q < dof; q++) { 10724 PetscInt rDof, rOff, r; 10725 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10726 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10727 for (r = 0; r < rDof; r++) { 10728 PetscInt s; 10729 10730 a = anchors[rOff + r]; 10731 if (a < sStart || a >= sEnd) continue; 10732 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10733 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10734 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10735 } 10736 } 10737 } 10738 } else { 10739 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10740 for (q = 0; q < dof; q++) { 10741 PetscInt rDof, rOff, r; 10742 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10743 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10744 for (r = 0; r < rDof; r++) { 10745 PetscInt s; 10746 10747 a = anchors[rOff + r]; 10748 if (a < sStart || a >= sEnd) continue; 10749 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10750 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10751 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10752 } 10753 } 10754 } 10755 } 10756 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10757 PetscCall(PetscFree(i)); 10758 PetscCall(PetscFree(j)); 10759 PetscCall(ISRestoreIndices(aIS, &anchors)); 10760 PetscFunctionReturn(PETSC_SUCCESS); 10761 } 10762 10763 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10764 { 10765 DM_Plex *plex = (DM_Plex *)dm->data; 10766 PetscSection anchorSection, section, cSec; 10767 Mat cMat; 10768 10769 PetscFunctionBegin; 10770 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10771 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10772 if (anchorSection) { 10773 PetscInt Nf; 10774 10775 PetscCall(DMGetLocalSection(dm, §ion)); 10776 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10777 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10778 PetscCall(DMGetNumFields(dm, &Nf)); 10779 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10780 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10781 PetscCall(PetscSectionDestroy(&cSec)); 10782 PetscCall(MatDestroy(&cMat)); 10783 } 10784 PetscFunctionReturn(PETSC_SUCCESS); 10785 } 10786 10787 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10788 { 10789 IS subis; 10790 PetscSection section, subsection; 10791 10792 PetscFunctionBegin; 10793 PetscCall(DMGetLocalSection(dm, §ion)); 10794 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10795 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10796 /* Create subdomain */ 10797 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10798 /* Create submodel */ 10799 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10800 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10801 PetscCall(DMSetLocalSection(*subdm, subsection)); 10802 PetscCall(PetscSectionDestroy(&subsection)); 10803 PetscCall(DMCopyDisc(dm, *subdm)); 10804 /* Create map from submodel to global model */ 10805 if (is) { 10806 PetscSection sectionGlobal, subsectionGlobal; 10807 IS spIS; 10808 const PetscInt *spmap; 10809 PetscInt *subIndices; 10810 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10811 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10812 10813 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10814 PetscCall(ISGetIndices(spIS, &spmap)); 10815 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10816 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10817 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10818 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10819 for (p = pStart; p < pEnd; ++p) { 10820 PetscInt gdof, pSubSize = 0; 10821 10822 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10823 if (gdof > 0) { 10824 for (f = 0; f < Nf; ++f) { 10825 PetscInt fdof, fcdof; 10826 10827 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10828 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10829 pSubSize += fdof - fcdof; 10830 } 10831 subSize += pSubSize; 10832 if (pSubSize) { 10833 if (bs < 0) { 10834 bs = pSubSize; 10835 } else if (bs != pSubSize) { 10836 /* Layout does not admit a pointwise block size */ 10837 bs = 1; 10838 } 10839 } 10840 } 10841 } 10842 /* Must have same blocksize on all procs (some might have no points) */ 10843 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10844 bsLocal[1] = bs; 10845 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10846 if (bsMinMax[0] != bsMinMax[1]) { 10847 bs = 1; 10848 } else { 10849 bs = bsMinMax[0]; 10850 } 10851 PetscCall(PetscMalloc1(subSize, &subIndices)); 10852 for (p = pStart; p < pEnd; ++p) { 10853 PetscInt gdof, goff; 10854 10855 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10856 if (gdof > 0) { 10857 const PetscInt point = spmap[p]; 10858 10859 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10860 for (f = 0; f < Nf; ++f) { 10861 PetscInt fdof, fcdof, fc, f2, poff = 0; 10862 10863 /* Can get rid of this loop by storing field information in the global section */ 10864 for (f2 = 0; f2 < f; ++f2) { 10865 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10866 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10867 poff += fdof - fcdof; 10868 } 10869 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10870 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10871 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10872 } 10873 } 10874 } 10875 PetscCall(ISRestoreIndices(spIS, &spmap)); 10876 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10877 if (bs > 1) { 10878 /* We need to check that the block size does not come from non-contiguous fields */ 10879 PetscInt i, j, set = 1; 10880 for (i = 0; i < subSize; i += bs) { 10881 for (j = 0; j < bs; ++j) { 10882 if (subIndices[i + j] != subIndices[i] + j) { 10883 set = 0; 10884 break; 10885 } 10886 } 10887 } 10888 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10889 } 10890 // Attach nullspace 10891 if (dm->nullspaceConstructors) { 10892 for (f = 0; f < Nf; ++f) { 10893 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10894 if ((*subdm)->nullspaceConstructors[f]) break; 10895 } 10896 if (f < Nf) { 10897 MatNullSpace nullSpace; 10898 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10899 10900 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10901 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10902 } 10903 } 10904 } 10905 PetscFunctionReturn(PETSC_SUCCESS); 10906 } 10907 10908 /*@ 10909 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10910 10911 Input Parameters: 10912 + dm - The `DM` 10913 - dummy - unused argument 10914 10915 Options Database Key: 10916 . -dm_plex_monitor_throughput - Activate the monitor 10917 10918 Level: developer 10919 10920 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10921 @*/ 10922 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10923 { 10924 PetscLogHandler default_handler; 10925 10926 PetscFunctionBegin; 10927 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10928 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10929 if (default_handler) { 10930 PetscLogEvent event; 10931 PetscEventPerfInfo eventInfo; 10932 PetscLogDouble cellRate, flopRate; 10933 PetscInt cStart, cEnd, Nf, N; 10934 const char *name; 10935 10936 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10937 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10938 PetscCall(DMGetNumFields(dm, &Nf)); 10939 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10940 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10941 N = (cEnd - cStart) * Nf * eventInfo.count; 10942 flopRate = eventInfo.flops / eventInfo.time; 10943 cellRate = N / eventInfo.time; 10944 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)); 10945 } else { 10946 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."); 10947 } 10948 PetscFunctionReturn(PETSC_SUCCESS); 10949 } 10950