1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_CreateBoxSFC, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 /* Logging support */ 18 PetscLogEvent DMPLEX_DistributionView, DMPLEX_DistributionLoad; 19 20 PetscBool Plexcite = PETSC_FALSE; 21 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 22 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 23 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 24 "journal = {SIAM Journal on Scientific Computing},\n" 25 "volume = {38},\n" 26 "number = {5},\n" 27 "pages = {S143--S155},\n" 28 "eprint = {http://arxiv.org/abs/1506.07749},\n" 29 "doi = {10.1137/15M1026092},\n" 30 "year = {2016},\n" 31 "petsc_uses={DMPlex},\n}\n"; 32 33 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 34 35 /*@ 36 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 37 38 Input Parameter: 39 . dm - The `DMPLEX` object 40 41 Output Parameter: 42 . simplex - Flag checking for a simplex 43 44 Level: intermediate 45 46 Note: 47 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 48 If the mesh has no cells, this returns `PETSC_FALSE`. 49 50 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 51 @*/ 52 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 53 { 54 DMPolytopeType ct; 55 PetscInt cStart, cEnd; 56 57 PetscFunctionBegin; 58 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 59 if (cEnd <= cStart) { 60 *simplex = PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 64 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 65 PetscFunctionReturn(PETSC_SUCCESS); 66 } 67 68 /*@ 69 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 70 71 Input Parameters: 72 + dm - The `DMPLEX` object 73 - height - The cell height in the Plex, 0 is the default 74 75 Output Parameters: 76 + cStart - The first "normal" cell, pass `NULL` if not needed 77 - cEnd - The upper bound on "normal" cells, pass `NULL` if not needed 78 79 Level: developer 80 81 Note: 82 This function requires that tensor cells are ordered last. 83 84 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 85 @*/ 86 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PeOp PetscInt *cStart, PeOp PetscInt *cEnd) 87 { 88 DMLabel ctLabel; 89 IS valueIS; 90 const PetscInt *ctypes; 91 PetscBool found = PETSC_FALSE; 92 PetscInt Nct, cS = PETSC_INT_MAX, cE = 0; 93 94 PetscFunctionBegin; 95 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 96 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 97 PetscCall(ISGetLocalSize(valueIS, &Nct)); 98 PetscCall(ISGetIndices(valueIS, &ctypes)); 99 for (PetscInt t = 0; t < Nct; ++t) { 100 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 101 PetscInt ctS, ctE, ht; 102 103 if (ct == DM_POLYTOPE_UNKNOWN) { 104 // If any cells are not typed, just use all cells 105 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 106 break; 107 } 108 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 109 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 110 if (ctS >= ctE) continue; 111 // Check that a point has the right height 112 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 113 if (ht != height) continue; 114 cS = PetscMin(cS, ctS); 115 cE = PetscMax(cE, ctE); 116 found = PETSC_TRUE; 117 } 118 if (!Nct || !found) cS = cE = 0; 119 PetscCall(ISDestroy(&valueIS)); 120 // Reset label for fast lookup 121 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 122 if (cStart) *cStart = cS; 123 if (cEnd) *cEnd = cE; 124 PetscFunctionReturn(PETSC_SUCCESS); 125 } 126 127 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 128 { 129 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 130 PetscInt *sStart, *sEnd; 131 PetscViewerVTKFieldType *ft; 132 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 133 DMLabel depthLabel, ctLabel; 134 135 PetscFunctionBegin; 136 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 137 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 138 PetscCall(DMGetCoordinateDim(dm, &cdim)); 139 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 140 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 141 if (field >= 0) { 142 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 143 } else { 144 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 145 } 146 147 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 148 PetscCall(DMPlexGetDepth(dm, &depth)); 149 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 150 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 151 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 152 const DMPolytopeType ict = (DMPolytopeType)c; 153 PetscInt dep; 154 155 if (ict == DM_POLYTOPE_FV_GHOST) continue; 156 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 157 if (pStart >= 0) { 158 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 159 if (dep != depth - cellHeight) continue; 160 } 161 if (field >= 0) { 162 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 163 } else { 164 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 165 } 166 } 167 168 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 169 *types = 0; 170 171 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 172 if (globalvcdof[c]) ++(*types); 173 } 174 175 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 176 t = 0; 177 if (globalvcdof[DM_NUM_POLYTOPES]) { 178 sStart[t] = vStart; 179 sEnd[t] = vEnd; 180 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 181 ++t; 182 } 183 184 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 185 if (globalvcdof[c]) { 186 const DMPolytopeType ict = (DMPolytopeType)c; 187 188 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 189 sStart[t] = cStart; 190 sEnd[t] = cEnd; 191 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 192 ++t; 193 } 194 } 195 196 if (!*types) { 197 if (field >= 0) { 198 const char *fieldname; 199 200 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 201 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 202 } else { 203 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 204 } 205 } 206 207 *ssStart = sStart; 208 *ssEnd = sEnd; 209 *sft = ft; 210 PetscFunctionReturn(PETSC_SUCCESS); 211 } 212 213 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 214 { 215 PetscFunctionBegin; 216 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 217 PetscFunctionReturn(PETSC_SUCCESS); 218 } 219 220 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 221 { 222 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 223 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 224 225 PetscFunctionBegin; 226 *ft = PETSC_VTK_INVALID; 227 PetscCall(DMGetCoordinateDim(dm, &cdim)); 228 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 229 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 230 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 231 if (field >= 0) { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 234 } else { 235 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 236 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 237 } 238 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 239 if (globalvcdof[0]) { 240 *sStart = vStart; 241 *sEnd = vEnd; 242 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 243 else *ft = PETSC_VTK_POINT_FIELD; 244 } else if (globalvcdof[1]) { 245 *sStart = cStart; 246 *sEnd = cEnd; 247 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 248 else *ft = PETSC_VTK_CELL_FIELD; 249 } else { 250 if (field >= 0) { 251 const char *fieldname; 252 253 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 254 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 255 } else { 256 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n")); 257 } 258 } 259 PetscFunctionReturn(PETSC_SUCCESS); 260 } 261 262 /*@ 263 DMPlexVecView1D - Plot many 1D solutions on the same line graph 264 265 Collective 266 267 Input Parameters: 268 + dm - The `DMPLEX` object 269 . n - The number of vectors 270 . u - The array of local vectors 271 - viewer - The `PetscViewer` 272 273 Level: advanced 274 275 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 276 @*/ 277 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 278 { 279 DM cdm; 280 PetscDS ds; 281 PetscDraw draw = NULL; 282 PetscDrawLG lg; 283 Vec coordinates; 284 const PetscScalar *coords, **sol; 285 PetscReal *vals; 286 PetscInt *Nc; 287 PetscInt Nf, Nl, vStart, vEnd, eStart, eEnd; 288 char **names; 289 290 PetscFunctionBegin; 291 PetscCall(DMGetCoordinateDM(dm, &cdm)); 292 PetscCall(DMGetDS(dm, &ds)); 293 PetscCall(PetscDSGetNumFields(ds, &Nf)); 294 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 295 PetscCall(PetscDSGetComponents(ds, &Nc)); 296 297 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 298 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 299 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 300 301 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 302 for (PetscInt i = 0, l = 0; i < n; ++i) { 303 const char *vname; 304 305 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 306 for (PetscInt f = 0; f < Nf; ++f) { 307 PetscObject disc; 308 const char *fname; 309 char tmpname[PETSC_MAX_PATH_LEN]; 310 311 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 312 /* TODO Create names for components */ 313 for (PetscInt c = 0; c < Nc[f]; ++c, ++l) { 314 PetscCall(PetscObjectGetName(disc, &fname)); 315 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 316 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 317 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 318 PetscCall(PetscStrallocpy(tmpname, &names[l])); 319 } 320 } 321 } 322 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 323 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 324 PetscCall(VecGetArrayRead(coordinates, &coords)); 325 for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 326 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 327 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 328 PetscSection s; 329 PetscInt cdof, vdof; 330 331 PetscCall(DMGetLocalSection(dm, &s)); 332 PetscCall(PetscSectionGetDof(s, eStart, &cdof)); 333 PetscCall(PetscSectionGetDof(s, vStart, &vdof)); 334 if (cdof) { 335 if (vdof) { 336 // P_2 337 PetscInt vFirst = -1; 338 339 for (PetscInt e = eStart; e < eEnd; ++e) { 340 PetscScalar *xa, *xb, *svals; 341 const PetscInt *cone; 342 343 PetscCall(DMPlexGetCone(dm, e, &cone)); 344 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 345 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 346 if (e == eStart) vFirst = cone[0]; 347 for (PetscInt i = 0; i < n; ++i) { 348 PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals)); 349 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 350 } 351 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals)); 352 if (e == eEnd - 1 && cone[1] != vFirst) { 353 for (PetscInt i = 0; i < n; ++i) { 354 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 355 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 356 } 357 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 358 for (PetscInt i = 0; i < n; ++i) { 359 PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals)); 360 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 361 } 362 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals)); 363 } 364 } 365 } else { 366 // P_0 367 for (PetscInt e = eStart; e < eEnd; ++e) { 368 PetscScalar *xa, *xb, *svals; 369 const PetscInt *cone; 370 371 PetscCall(DMPlexGetCone(dm, e, &cone)); 372 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 373 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 374 for (PetscInt i = 0; i < n; ++i) { 375 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 376 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 377 } 378 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 379 } 380 } 381 } else if (vdof) { 382 // P_1 383 for (PetscInt v = vStart; v < vEnd; ++v) { 384 PetscScalar *x, *svals; 385 386 PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x)); 387 for (PetscInt i = 0; i < n; ++i) { 388 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 389 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 390 } 391 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 392 } 393 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Discretization not supported"); 394 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 395 for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 396 for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 397 PetscCall(PetscFree3(sol, names, vals)); 398 399 PetscCall(PetscDrawLGDraw(lg)); 400 PetscCall(PetscDrawLGDestroy(&lg)); 401 PetscFunctionReturn(PETSC_SUCCESS); 402 } 403 404 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 405 { 406 DM dm; 407 408 PetscFunctionBegin; 409 PetscCall(VecGetDM(u, &dm)); 410 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 411 PetscFunctionReturn(PETSC_SUCCESS); 412 } 413 414 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 415 { 416 DM dm; 417 PetscSection s; 418 PetscDraw draw, popup; 419 DM cdm; 420 PetscSection coordSection; 421 Vec coordinates; 422 const PetscScalar *array; 423 PetscReal lbound[3], ubound[3]; 424 PetscReal vbound[2], time; 425 PetscBool flg; 426 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 427 const char *name; 428 char title[PETSC_MAX_PATH_LEN]; 429 430 PetscFunctionBegin; 431 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 432 PetscCall(VecGetDM(v, &dm)); 433 PetscCall(DMGetCoordinateDim(dm, &dim)); 434 PetscCall(DMGetLocalSection(dm, &s)); 435 PetscCall(PetscSectionGetNumFields(s, &Nf)); 436 PetscCall(DMGetCoarsenLevel(dm, &level)); 437 PetscCall(DMGetCoordinateDM(dm, &cdm)); 438 PetscCall(DMGetLocalSection(cdm, &coordSection)); 439 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 440 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 441 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 442 443 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 444 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 445 446 PetscCall(VecGetLocalSize(coordinates, &N)); 447 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 448 PetscCall(PetscDrawClear(draw)); 449 450 /* Could implement something like DMDASelectFields() */ 451 for (f = 0; f < Nf; ++f) { 452 DM fdm = dm; 453 Vec fv = v; 454 IS fis; 455 char prefix[PETSC_MAX_PATH_LEN]; 456 const char *fname; 457 458 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 459 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 460 461 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 462 else prefix[0] = '\0'; 463 if (Nf > 1) { 464 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 465 PetscCall(VecGetSubVector(v, fis, &fv)); 466 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 467 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 468 } 469 for (comp = 0; comp < Nc; ++comp, ++w) { 470 PetscInt nmax = 2; 471 472 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 473 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 474 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 475 PetscCall(PetscDrawSetTitle(draw, title)); 476 477 /* TODO Get max and min only for this component */ 478 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 479 if (!flg) { 480 PetscCall(VecMin(fv, NULL, &vbound[0])); 481 PetscCall(VecMax(fv, NULL, &vbound[1])); 482 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 483 } 484 485 PetscCall(PetscDrawGetPopup(draw, &popup)); 486 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 487 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 488 PetscCall(VecGetArrayRead(fv, &array)); 489 for (c = cStart; c < cEnd; ++c) { 490 DMPolytopeType ct; 491 PetscScalar *coords = NULL, *a = NULL; 492 const PetscScalar *coords_arr; 493 PetscBool isDG; 494 PetscInt numCoords; 495 int color[4] = {-1, -1, -1, -1}; 496 497 PetscCall(DMPlexGetCellType(dm, c, &ct)); 498 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 499 if (a) { 500 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 501 color[1] = color[2] = color[3] = color[0]; 502 } else { 503 PetscScalar *vals = NULL; 504 PetscInt numVals, va; 505 506 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 507 if (!numVals) { 508 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 509 continue; 510 } 511 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 512 switch (numVals / Nc) { 513 case 1: /* P1 Clamped Segment Prism */ 514 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 515 PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]); 516 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 517 break; 518 case 3: /* P1 Triangle */ 519 case 4: /* P1 Quadrangle */ 520 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 521 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 522 break; 523 case 6: /* P2 Triangle */ 524 case 8: /* P2 Quadrangle */ 525 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 526 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 527 break; 528 default: 529 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 530 } 531 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 532 } 533 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 534 switch (numCoords) { 535 case 6: 536 case 12: /* Localized triangle */ 537 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 538 break; 539 case 8: 540 case 16: /* Localized quadrilateral */ 541 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 542 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 543 } else { 544 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 545 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 546 } 547 break; 548 default: 549 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 550 } 551 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 552 } 553 PetscCall(VecRestoreArrayRead(fv, &array)); 554 PetscCall(PetscDrawFlush(draw)); 555 PetscCall(PetscDrawPause(draw)); 556 PetscCall(PetscDrawSave(draw)); 557 } 558 if (Nf > 1) { 559 PetscCall(VecRestoreSubVector(v, fis, &fv)); 560 PetscCall(ISDestroy(&fis)); 561 PetscCall(DMDestroy(&fdm)); 562 } 563 } 564 PetscFunctionReturn(PETSC_SUCCESS); 565 } 566 567 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 568 { 569 DM dm; 570 PetscDraw draw; 571 PetscInt dim; 572 PetscBool isnull; 573 574 PetscFunctionBegin; 575 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 576 PetscCall(PetscDrawIsNull(draw, &isnull)); 577 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 578 579 PetscCall(VecGetDM(v, &dm)); 580 PetscCall(DMGetCoordinateDim(dm, &dim)); 581 switch (dim) { 582 case 1: 583 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 584 break; 585 case 2: 586 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 587 break; 588 default: 589 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 590 } 591 PetscFunctionReturn(PETSC_SUCCESS); 592 } 593 594 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 595 { 596 DM dm; 597 Vec locv; 598 const char *name; 599 PetscSection section; 600 PetscInt pStart, pEnd; 601 PetscInt numFields; 602 PetscViewerVTKFieldType ft; 603 604 PetscFunctionBegin; 605 PetscCall(VecGetDM(v, &dm)); 606 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 607 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 608 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 609 PetscCall(VecCopy(v, locv)); 610 PetscCall(DMGetLocalSection(dm, §ion)); 611 PetscCall(PetscSectionGetNumFields(section, &numFields)); 612 if (!numFields) { 613 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 614 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 615 } else { 616 PetscInt f; 617 618 for (f = 0; f < numFields; f++) { 619 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 620 if (ft == PETSC_VTK_INVALID) continue; 621 PetscCall(PetscObjectReference((PetscObject)locv)); 622 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 623 } 624 PetscCall(VecDestroy(&locv)); 625 } 626 PetscFunctionReturn(PETSC_SUCCESS); 627 } 628 629 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 630 { 631 DM dm; 632 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython; 633 634 PetscFunctionBegin; 635 PetscCall(VecGetDM(v, &dm)); 636 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 640 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 641 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 642 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 643 if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) { 644 PetscInt i, numFields; 645 PetscObject fe; 646 PetscBool fem = PETSC_FALSE; 647 Vec locv = v; 648 const char *name; 649 PetscInt step; 650 PetscReal time; 651 652 PetscCall(DMGetNumFields(dm, &numFields)); 653 for (i = 0; i < numFields; i++) { 654 PetscCall(DMGetField(dm, i, NULL, &fe)); 655 if (fe->classid == PETSCFE_CLASSID) { 656 fem = PETSC_TRUE; 657 break; 658 } 659 } 660 if (fem) { 661 PetscObject isZero; 662 663 PetscCall(DMGetLocalVector(dm, &locv)); 664 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 665 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 666 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 667 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 668 PetscCall(VecCopy(v, locv)); 669 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 670 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 671 } 672 if (isvtk) { 673 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 674 } else if (ishdf5) { 675 #if defined(PETSC_HAVE_HDF5) 676 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 677 #else 678 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 679 #endif 680 } else if (isdraw) { 681 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 682 } else if (ispython) { 683 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv)); 684 } else if (isglvis) { 685 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 686 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 687 PetscCall(VecView_GLVis(locv, viewer)); 688 } else if (iscgns) { 689 #if defined(PETSC_HAVE_CGNS) 690 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 691 #else 692 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 693 #endif 694 } 695 if (fem) { 696 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 697 PetscCall(DMRestoreLocalVector(dm, &locv)); 698 } 699 } else { 700 PetscBool isseq; 701 702 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 703 if (isseq) PetscCall(VecView_Seq(v, viewer)); 704 else PetscCall(VecView_MPI(v, viewer)); 705 } 706 PetscFunctionReturn(PETSC_SUCCESS); 707 } 708 709 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 710 { 711 DM dm; 712 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython; 713 714 PetscFunctionBegin; 715 PetscCall(VecGetDM(v, &dm)); 716 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 721 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 722 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 723 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 724 if (isvtk || isdraw || isglvis || iscgns || ispython) { 725 Vec locv; 726 PetscObject isZero; 727 const char *name; 728 729 PetscCall(DMGetLocalVector(dm, &locv)); 730 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 731 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 732 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 733 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 734 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 735 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 736 PetscCall(VecView_Plex_Local(locv, viewer)); 737 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 738 PetscCall(DMRestoreLocalVector(dm, &locv)); 739 } else if (ishdf5) { 740 #if defined(PETSC_HAVE_HDF5) 741 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 742 #else 743 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 744 #endif 745 } else if (isexodusii) { 746 #if defined(PETSC_HAVE_EXODUSII) 747 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 748 #else 749 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 750 #endif 751 } else { 752 PetscBool isseq; 753 754 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 755 if (isseq) PetscCall(VecView_Seq(v, viewer)); 756 else PetscCall(VecView_MPI(v, viewer)); 757 } 758 PetscFunctionReturn(PETSC_SUCCESS); 759 } 760 761 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 762 { 763 DM dm; 764 MPI_Comm comm; 765 PetscViewerFormat format; 766 Vec v; 767 PetscBool isvtk, ishdf5; 768 769 PetscFunctionBegin; 770 PetscCall(VecGetDM(originalv, &dm)); 771 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 772 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 773 PetscCall(PetscViewerGetFormat(viewer, &format)); 774 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 775 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 776 if (format == PETSC_VIEWER_NATIVE) { 777 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 778 /* this need a better fix */ 779 if (dm->useNatural) { 780 if (dm->sfNatural) { 781 const char *vecname; 782 PetscInt n, nroots; 783 784 PetscCall(VecGetLocalSize(originalv, &n)); 785 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 786 if (n == nroots) { 787 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 788 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 789 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 790 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 791 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 792 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 793 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 794 } else v = originalv; 795 } else v = originalv; 796 797 if (ishdf5) { 798 #if defined(PETSC_HAVE_HDF5) 799 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 800 #else 801 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 802 #endif 803 } else if (isvtk) { 804 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 805 } else { 806 PetscBool isseq; 807 808 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 809 if (isseq) PetscCall(VecView_Seq(v, viewer)); 810 else PetscCall(VecView_MPI(v, viewer)); 811 } 812 if (v != originalv) PetscCall(VecDestroy(&v)); 813 PetscFunctionReturn(PETSC_SUCCESS); 814 } 815 816 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 817 { 818 DM dm; 819 PetscBool ishdf5; 820 821 PetscFunctionBegin; 822 PetscCall(VecGetDM(v, &dm)); 823 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 824 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 825 if (ishdf5) { 826 DM dmBC; 827 Vec gv; 828 const char *name; 829 830 PetscCall(DMGetOutputDM(dm, &dmBC)); 831 PetscCall(DMGetGlobalVector(dmBC, &gv)); 832 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 833 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 834 PetscCall(VecLoad_Default(gv, viewer)); 835 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 836 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 837 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 838 } else PetscCall(VecLoad_Default(v, viewer)); 839 PetscFunctionReturn(PETSC_SUCCESS); 840 } 841 842 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 843 { 844 DM dm; 845 PetscBool ishdf5, isexodusii, iscgns; 846 847 PetscFunctionBegin; 848 PetscCall(VecGetDM(v, &dm)); 849 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 850 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 851 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 852 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 853 if (ishdf5) { 854 #if defined(PETSC_HAVE_HDF5) 855 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 856 #else 857 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 858 #endif 859 } else if (isexodusii) { 860 #if defined(PETSC_HAVE_EXODUSII) 861 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 862 #else 863 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 864 #endif 865 } else if (iscgns) { 866 #if defined(PETSC_HAVE_CGNS) 867 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 868 #else 869 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 870 #endif 871 } else PetscCall(VecLoad_Default(v, viewer)); 872 PetscFunctionReturn(PETSC_SUCCESS); 873 } 874 875 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 876 { 877 DM dm; 878 PetscViewerFormat format; 879 PetscBool ishdf5; 880 881 PetscFunctionBegin; 882 PetscCall(VecGetDM(originalv, &dm)); 883 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 884 PetscCall(PetscViewerGetFormat(viewer, &format)); 885 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 886 if (format == PETSC_VIEWER_NATIVE) { 887 if (dm->useNatural) { 888 if (dm->sfNatural) { 889 if (ishdf5) { 890 #if defined(PETSC_HAVE_HDF5) 891 Vec v; 892 const char *vecname; 893 894 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 895 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 896 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 897 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 898 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 899 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 900 PetscCall(VecDestroy(&v)); 901 #else 902 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 903 #endif 904 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 905 } 906 } else PetscCall(VecLoad_Default(originalv, viewer)); 907 } 908 PetscFunctionReturn(PETSC_SUCCESS); 909 } 910 911 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 912 { 913 PetscSection coordSection; 914 Vec coordinates; 915 DMLabel depthLabel, celltypeLabel; 916 const char *name[4]; 917 const PetscScalar *a; 918 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 919 920 PetscFunctionBegin; 921 PetscCall(DMGetDimension(dm, &dim)); 922 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 923 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 924 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 925 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 926 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 927 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 928 PetscCall(VecGetArrayRead(coordinates, &a)); 929 name[0] = "vertex"; 930 name[1] = "edge"; 931 name[dim - 1] = "face"; 932 name[dim] = "cell"; 933 for (c = cStart; c < cEnd; ++c) { 934 PetscInt *closure = NULL; 935 PetscInt closureSize, cl, ct; 936 937 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 938 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 939 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 940 PetscCall(PetscViewerASCIIPushTab(viewer)); 941 for (cl = 0; cl < closureSize * 2; cl += 2) { 942 PetscInt point = closure[cl], depth, dof, off, d, p; 943 944 if ((point < pStart) || (point >= pEnd)) continue; 945 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 946 if (!dof) continue; 947 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 948 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 949 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 950 for (p = 0; p < dof / dim; ++p) { 951 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 952 for (d = 0; d < dim; ++d) { 953 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 955 } 956 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 957 } 958 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 959 } 960 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 961 PetscCall(PetscViewerASCIIPopTab(viewer)); 962 } 963 PetscCall(VecRestoreArrayRead(coordinates, &a)); 964 PetscFunctionReturn(PETSC_SUCCESS); 965 } 966 967 typedef enum { 968 CS_CARTESIAN, 969 CS_POLAR, 970 CS_CYLINDRICAL, 971 CS_SPHERICAL 972 } CoordSystem; 973 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 974 975 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 976 { 977 PetscInt i; 978 979 PetscFunctionBegin; 980 if (dim > 3) { 981 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 982 } else { 983 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 984 985 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 986 switch (cs) { 987 case CS_CARTESIAN: 988 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 989 break; 990 case CS_POLAR: 991 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 992 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 993 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 994 break; 995 case CS_CYLINDRICAL: 996 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 997 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 998 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 999 trcoords[2] = coords[2]; 1000 break; 1001 case CS_SPHERICAL: 1002 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 1003 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 1004 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 1005 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 1006 break; 1007 } 1008 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 1009 } 1010 PetscFunctionReturn(PETSC_SUCCESS); 1011 } 1012 1013 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 1014 { 1015 DM_Plex *mesh = (DM_Plex *)dm->data; 1016 DM cdm, cdmCell; 1017 PetscSection coordSection, coordSectionCell; 1018 Vec coordinates, coordinatesCell; 1019 PetscViewerFormat format; 1020 1021 PetscFunctionBegin; 1022 PetscCall(PetscViewerGetFormat(viewer, &format)); 1023 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1024 const char *name; 1025 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1026 PetscInt pStart, pEnd, p, numLabels, l; 1027 PetscMPIInt rank, size; 1028 1029 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1030 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1031 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1032 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1033 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1034 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1035 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1036 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1037 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1038 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1039 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1040 PetscCall(DMGetDimension(dm, &dim)); 1041 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1042 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1043 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1044 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1045 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1046 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1047 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1048 for (p = pStart; p < pEnd; ++p) { 1049 PetscInt dof, off, s; 1050 1051 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1052 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1053 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1054 } 1055 PetscCall(PetscViewerFlush(viewer)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1057 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1058 for (p = pStart; p < pEnd; ++p) { 1059 PetscInt dof, off, c; 1060 1061 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1062 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1063 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 1064 } 1065 PetscCall(PetscViewerFlush(viewer)); 1066 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1067 if (coordSection && coordinates) { 1068 CoordSystem cs = CS_CARTESIAN; 1069 const PetscScalar *array, *arrayCell = NULL; 1070 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1071 PetscMPIInt rank; 1072 const char *name; 1073 1074 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1075 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1076 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1077 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1078 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1079 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1080 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1081 pStart = PetscMin(pvStart, pcStart); 1082 pEnd = PetscMax(pvEnd, pcEnd); 1083 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1084 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1085 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1086 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1087 1088 PetscCall(VecGetArrayRead(coordinates, &array)); 1089 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1090 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1091 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1092 for (p = pStart; p < pEnd; ++p) { 1093 PetscInt dof, off; 1094 1095 if (p >= pvStart && p < pvEnd) { 1096 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1097 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1098 if (dof) { 1099 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1100 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1101 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1102 } 1103 } 1104 if (cdmCell && p >= pcStart && p < pcEnd) { 1105 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1106 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1107 if (dof) { 1108 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1109 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1110 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1111 } 1112 } 1113 } 1114 PetscCall(PetscViewerFlush(viewer)); 1115 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1116 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1117 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1118 } 1119 PetscCall(DMGetNumLabels(dm, &numLabels)); 1120 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1121 for (l = 0; l < numLabels; ++l) { 1122 DMLabel label; 1123 PetscBool isdepth; 1124 const char *name; 1125 1126 PetscCall(DMGetLabelName(dm, l, &name)); 1127 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1128 if (isdepth) continue; 1129 PetscCall(DMGetLabel(dm, name, &label)); 1130 PetscCall(DMLabelView(label, viewer)); 1131 } 1132 if (size > 1) { 1133 PetscSF sf; 1134 1135 PetscCall(DMGetPointSF(dm, &sf)); 1136 PetscCall(PetscSFView(sf, viewer)); 1137 } 1138 if (mesh->periodic.face_sfs) 1139 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1140 PetscCall(PetscViewerFlush(viewer)); 1141 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1142 const char *name, *color; 1143 const char *defcolors[3] = {"gray", "orange", "green"}; 1144 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1145 char lname[PETSC_MAX_PATH_LEN]; 1146 PetscReal scale = 2.0; 1147 PetscReal tikzscale = 1.0; 1148 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1149 double tcoords[3]; 1150 PetscScalar *coords; 1151 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 1152 PetscMPIInt rank, size; 1153 char **names, **colors, **lcolors; 1154 PetscBool flg, lflg; 1155 PetscBT wp = NULL; 1156 PetscInt pEnd, pStart; 1157 1158 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1159 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1160 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1161 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1162 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1163 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1164 PetscCall(DMGetDimension(dm, &dim)); 1165 PetscCall(DMPlexGetDepth(dm, &depth)); 1166 PetscCall(DMGetNumLabels(dm, &numLabels)); 1167 numLabels = PetscMax(numLabels, 10); 1168 numColors = 10; 1169 numLColors = 10; 1170 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1171 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1172 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1173 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1174 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1175 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1176 n = 4; 1177 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1178 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1179 n = 4; 1180 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1181 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1182 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1183 if (!useLabels) numLabels = 0; 1184 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1185 if (!useColors) { 1186 numColors = 3; 1187 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1188 } 1189 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1190 if (!useColors) { 1191 numLColors = 4; 1192 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1193 } 1194 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1195 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1196 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1197 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1198 if (depth < dim) plotEdges = PETSC_FALSE; 1199 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1200 1201 /* filter points with labelvalue != labeldefaultvalue */ 1202 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1203 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1204 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1205 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1206 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1207 if (lflg) { 1208 DMLabel lbl; 1209 1210 PetscCall(DMGetLabel(dm, lname, &lbl)); 1211 if (lbl) { 1212 PetscInt val, defval; 1213 1214 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1215 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1216 for (c = pStart; c < pEnd; c++) { 1217 PetscInt *closure = NULL; 1218 PetscInt closureSize; 1219 1220 PetscCall(DMLabelGetValue(lbl, c, &val)); 1221 if (val == defval) continue; 1222 1223 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1224 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1225 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1226 } 1227 } 1228 } 1229 1230 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1231 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1232 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1234 \\documentclass[tikz]{standalone}\n\n\ 1235 \\usepackage{pgflibraryshapes}\n\ 1236 \\usetikzlibrary{backgrounds}\n\ 1237 \\usetikzlibrary{arrows}\n\ 1238 \\begin{document}\n")); 1239 if (size > 1) { 1240 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1241 for (p = 0; p < size; ++p) { 1242 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1243 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1244 } 1245 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1246 } 1247 if (drawHasse) { 1248 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1249 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1258 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1264 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1265 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1266 } 1267 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1268 1269 /* Plot vertices */ 1270 PetscCall(VecGetArray(coordinates, &coords)); 1271 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1272 for (v = vStart; v < vEnd; ++v) { 1273 PetscInt off, dof, d; 1274 PetscBool isLabeled = PETSC_FALSE; 1275 1276 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1277 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1278 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1280 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1281 for (d = 0; d < dof; ++d) { 1282 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1283 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1284 } 1285 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1286 if (dim == 3) { 1287 PetscReal tmp = tcoords[1]; 1288 tcoords[1] = tcoords[2]; 1289 tcoords[2] = -tmp; 1290 } 1291 for (d = 0; d < dof; ++d) { 1292 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1293 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1294 } 1295 if (drawHasse) color = colors[0 % numColors]; 1296 else color = colors[rank % numColors]; 1297 for (l = 0; l < numLabels; ++l) { 1298 PetscInt val; 1299 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1300 if (val >= 0) { 1301 color = lcolors[l % numLColors]; 1302 isLabeled = PETSC_TRUE; 1303 break; 1304 } 1305 } 1306 if (drawNumbers[0]) { 1307 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1308 } else if (drawColors[0]) { 1309 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1310 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1311 } 1312 PetscCall(VecRestoreArray(coordinates, &coords)); 1313 PetscCall(PetscViewerFlush(viewer)); 1314 /* Plot edges */ 1315 if (plotEdges) { 1316 PetscCall(VecGetArray(coordinates, &coords)); 1317 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1318 for (e = eStart; e < eEnd; ++e) { 1319 const PetscInt *cone; 1320 PetscInt coneSize, offA, offB, dof, d; 1321 1322 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1323 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1324 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1325 PetscCall(DMPlexGetCone(dm, e, &cone)); 1326 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1327 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1328 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1329 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1330 for (d = 0; d < dof; ++d) { 1331 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1332 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1333 } 1334 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1335 if (dim == 3) { 1336 PetscReal tmp = tcoords[1]; 1337 tcoords[1] = tcoords[2]; 1338 tcoords[2] = -tmp; 1339 } 1340 for (d = 0; d < dof; ++d) { 1341 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1342 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1343 } 1344 if (drawHasse) color = colors[1 % numColors]; 1345 else color = colors[rank % numColors]; 1346 for (l = 0; l < numLabels; ++l) { 1347 PetscInt val; 1348 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1349 if (val >= 0) { 1350 color = lcolors[l % numLColors]; 1351 break; 1352 } 1353 } 1354 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1355 } 1356 PetscCall(VecRestoreArray(coordinates, &coords)); 1357 PetscCall(PetscViewerFlush(viewer)); 1358 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1359 } 1360 /* Plot cells */ 1361 if (dim == 3 || !drawNumbers[1]) { 1362 for (e = eStart; e < eEnd; ++e) { 1363 const PetscInt *cone; 1364 1365 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1366 color = colors[rank % numColors]; 1367 for (l = 0; l < numLabels; ++l) { 1368 PetscInt val; 1369 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1370 if (val >= 0) { 1371 color = lcolors[l % numLColors]; 1372 break; 1373 } 1374 } 1375 PetscCall(DMPlexGetCone(dm, e, &cone)); 1376 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1377 } 1378 } else { 1379 DMPolytopeType ct; 1380 1381 /* Drawing a 2D polygon */ 1382 for (c = cStart; c < cEnd; ++c) { 1383 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1384 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1385 if (DMPolytopeTypeIsHybrid(ct)) { 1386 const PetscInt *cone; 1387 PetscInt coneSize, e; 1388 1389 PetscCall(DMPlexGetCone(dm, c, &cone)); 1390 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1391 for (e = 0; e < coneSize; ++e) { 1392 const PetscInt *econe; 1393 1394 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1395 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1396 } 1397 } else { 1398 PetscInt *closure = NULL; 1399 PetscInt closureSize, Nv = 0, v; 1400 1401 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1402 for (p = 0; p < closureSize * 2; p += 2) { 1403 const PetscInt point = closure[p]; 1404 1405 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1406 } 1407 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1408 for (v = 0; v <= Nv; ++v) { 1409 const PetscInt vertex = closure[v % Nv]; 1410 1411 if (v > 0) { 1412 if (plotEdges) { 1413 const PetscInt *edge; 1414 PetscInt endpoints[2], ne; 1415 1416 endpoints[0] = closure[v - 1]; 1417 endpoints[1] = vertex; 1418 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1419 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1420 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1421 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1422 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1423 } 1424 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1425 } 1426 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1427 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1428 } 1429 } 1430 } 1431 for (c = cStart; c < cEnd; ++c) { 1432 double ccoords[3] = {0.0, 0.0, 0.0}; 1433 PetscBool isLabeled = PETSC_FALSE; 1434 PetscScalar *cellCoords = NULL; 1435 const PetscScalar *array; 1436 PetscInt numCoords, cdim, d; 1437 PetscBool isDG; 1438 1439 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1440 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1441 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1442 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1443 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1444 for (p = 0; p < numCoords / cdim; ++p) { 1445 for (d = 0; d < cdim; ++d) { 1446 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1447 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1448 } 1449 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1450 if (cdim == 3) { 1451 PetscReal tmp = tcoords[1]; 1452 tcoords[1] = tcoords[2]; 1453 tcoords[2] = -tmp; 1454 } 1455 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1456 } 1457 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1458 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1459 for (d = 0; d < cdim; ++d) { 1460 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1461 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1462 } 1463 if (drawHasse) color = colors[depth % numColors]; 1464 else color = colors[rank % numColors]; 1465 for (l = 0; l < numLabels; ++l) { 1466 PetscInt val; 1467 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1468 if (val >= 0) { 1469 color = lcolors[l % numLColors]; 1470 isLabeled = PETSC_TRUE; 1471 break; 1472 } 1473 } 1474 if (drawNumbers[dim]) { 1475 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1476 } else if (drawColors[dim]) { 1477 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1478 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1479 } 1480 if (drawHasse) { 1481 int height = 0; 1482 1483 color = colors[depth % numColors]; 1484 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1485 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1486 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1487 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1489 1490 if (depth > 2) { 1491 color = colors[1 % numColors]; 1492 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1493 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1494 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1495 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1496 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1497 } 1498 1499 color = colors[1 % numColors]; 1500 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1502 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1503 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1504 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1505 1506 color = colors[0 % numColors]; 1507 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1510 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1511 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1512 1513 for (p = pStart; p < pEnd; ++p) { 1514 const PetscInt *cone; 1515 PetscInt coneSize, cp; 1516 1517 PetscCall(DMPlexGetCone(dm, p, &cone)); 1518 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1519 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1520 } 1521 } 1522 PetscCall(PetscViewerFlush(viewer)); 1523 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1524 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1525 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1526 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1527 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1528 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1529 PetscCall(PetscFree3(names, colors, lcolors)); 1530 PetscCall(PetscBTDestroy(&wp)); 1531 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1532 Vec cown, acown; 1533 VecScatter sct; 1534 ISLocalToGlobalMapping g2l; 1535 IS gid, acis; 1536 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1537 MPI_Group ggroup, ngroup; 1538 PetscScalar *array, nid; 1539 const PetscInt *idxs; 1540 PetscInt *idxs2, *start, *adjacency, *work; 1541 PetscInt64 lm[3], gm[3]; 1542 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1543 PetscMPIInt d1, d2, rank; 1544 1545 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1546 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1547 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1548 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1549 #endif 1550 if (ncomm != MPI_COMM_NULL) { 1551 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1552 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1553 d1 = 0; 1554 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1555 nid = d2; 1556 PetscCallMPI(MPI_Group_free(&ggroup)); 1557 PetscCallMPI(MPI_Group_free(&ngroup)); 1558 PetscCallMPI(MPI_Comm_free(&ncomm)); 1559 } else nid = 0.0; 1560 1561 /* Get connectivity */ 1562 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1563 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1564 1565 /* filter overlapped local cells */ 1566 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1567 PetscCall(ISGetIndices(gid, &idxs)); 1568 PetscCall(ISGetLocalSize(gid, &cum)); 1569 PetscCall(PetscMalloc1(cum, &idxs2)); 1570 for (c = cStart, cum = 0; c < cEnd; c++) { 1571 if (idxs[c - cStart] < 0) continue; 1572 idxs2[cum++] = idxs[c - cStart]; 1573 } 1574 PetscCall(ISRestoreIndices(gid, &idxs)); 1575 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1576 PetscCall(ISDestroy(&gid)); 1577 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1578 1579 /* support for node-aware cell locality */ 1580 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1581 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1582 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1583 PetscCall(VecGetArray(cown, &array)); 1584 for (c = 0; c < numVertices; c++) array[c] = nid; 1585 PetscCall(VecRestoreArray(cown, &array)); 1586 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1587 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1588 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1589 PetscCall(ISDestroy(&acis)); 1590 PetscCall(VecScatterDestroy(&sct)); 1591 PetscCall(VecDestroy(&cown)); 1592 1593 /* compute edgeCut */ 1594 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1595 PetscCall(PetscMalloc1(cum, &work)); 1596 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1597 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1598 PetscCall(ISDestroy(&gid)); 1599 PetscCall(VecGetArray(acown, &array)); 1600 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1601 PetscInt totl; 1602 1603 totl = start[c + 1] - start[c]; 1604 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1605 for (i = 0; i < totl; i++) { 1606 if (work[i] < 0) { 1607 ect += 1; 1608 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1609 } 1610 } 1611 } 1612 PetscCall(PetscFree(work)); 1613 PetscCall(VecRestoreArray(acown, &array)); 1614 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1615 lm[1] = -numVertices; 1616 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1617 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1618 lm[0] = ect; /* edgeCut */ 1619 lm[1] = ectn; /* node-aware edgeCut */ 1620 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1621 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1622 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1623 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1624 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1625 #else 1626 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1627 #endif 1628 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1629 PetscCall(PetscFree(start)); 1630 PetscCall(PetscFree(adjacency)); 1631 PetscCall(VecDestroy(&acown)); 1632 } else { 1633 const char *name; 1634 PetscInt *sizes, *hybsizes, *ghostsizes; 1635 PetscInt locDepth, depth, cellHeight, dim, d; 1636 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1637 PetscInt numLabels, l, maxSize = 17; 1638 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1639 MPI_Comm comm; 1640 PetscMPIInt size, rank; 1641 1642 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1643 PetscCallMPI(MPI_Comm_size(comm, &size)); 1644 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1645 PetscCall(DMGetDimension(dm, &dim)); 1646 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1647 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1648 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1649 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1650 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1651 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1652 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1653 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1654 gcNum = gcEnd - gcStart; 1655 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1656 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1657 for (d = 0; d <= depth; d++) { 1658 PetscInt Nc[2] = {0, 0}, ict; 1659 1660 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1661 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1662 ict = ct0; 1663 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1664 ct0 = (DMPolytopeType)ict; 1665 for (p = pStart; p < pEnd; ++p) { 1666 DMPolytopeType ct; 1667 1668 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1669 if (ct == ct0) ++Nc[0]; 1670 else ++Nc[1]; 1671 } 1672 if (size < maxSize) { 1673 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1674 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1675 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1676 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1677 for (p = 0; p < size; ++p) { 1678 if (rank == 0) { 1679 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1680 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1681 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1682 } 1683 } 1684 } else { 1685 PetscInt locMinMax[2]; 1686 1687 locMinMax[0] = Nc[0] + Nc[1]; 1688 locMinMax[1] = Nc[0] + Nc[1]; 1689 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1690 locMinMax[0] = Nc[1]; 1691 locMinMax[1] = Nc[1]; 1692 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1693 if (d == depth) { 1694 locMinMax[0] = gcNum; 1695 locMinMax[1] = gcNum; 1696 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1697 } 1698 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1699 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1700 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1701 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1702 } 1703 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1704 } 1705 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1706 { 1707 const PetscReal *maxCell; 1708 const PetscReal *L; 1709 PetscBool localized; 1710 1711 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1712 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1713 if (L || localized) { 1714 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1715 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1716 if (L) { 1717 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1718 for (d = 0; d < dim; ++d) { 1719 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1720 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1721 } 1722 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1723 } 1724 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1725 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1726 } 1727 } 1728 PetscCall(DMGetNumLabels(dm, &numLabels)); 1729 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1730 for (l = 0; l < numLabels; ++l) { 1731 DMLabel label; 1732 const char *name; 1733 PetscInt *values; 1734 PetscInt numValues, v; 1735 1736 PetscCall(DMGetLabelName(dm, l, &name)); 1737 PetscCall(DMGetLabel(dm, name, &label)); 1738 PetscCall(DMLabelGetNumValues(label, &numValues)); 1739 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1740 1741 { // Extract array of DMLabel values so it can be sorted 1742 IS is_values; 1743 const PetscInt *is_values_local = NULL; 1744 1745 PetscCall(DMLabelGetValueIS(label, &is_values)); 1746 PetscCall(ISGetIndices(is_values, &is_values_local)); 1747 PetscCall(PetscMalloc1(numValues, &values)); 1748 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1749 PetscCall(PetscSortInt(numValues, values)); 1750 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1751 PetscCall(ISDestroy(&is_values)); 1752 } 1753 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1754 for (v = 0; v < numValues; ++v) { 1755 PetscInt size; 1756 1757 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1758 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1759 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1760 } 1761 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1762 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1763 PetscCall(PetscFree(values)); 1764 } 1765 { 1766 char **labelNames; 1767 PetscInt Nl = numLabels; 1768 PetscBool flg; 1769 1770 PetscCall(PetscMalloc1(Nl, &labelNames)); 1771 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1772 for (l = 0; l < Nl; ++l) { 1773 DMLabel label; 1774 1775 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1776 if (flg) { 1777 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1778 PetscCall(DMLabelView(label, viewer)); 1779 } 1780 PetscCall(PetscFree(labelNames[l])); 1781 } 1782 PetscCall(PetscFree(labelNames)); 1783 } 1784 /* If no fields are specified, people do not want to see adjacency */ 1785 if (dm->Nf) { 1786 PetscInt f; 1787 1788 for (f = 0; f < dm->Nf; ++f) { 1789 const char *name; 1790 1791 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1792 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1793 PetscCall(PetscViewerASCIIPushTab(viewer)); 1794 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1795 if (dm->fields[f].adjacency[0]) { 1796 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1797 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1798 } else { 1799 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1800 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1801 } 1802 PetscCall(PetscViewerASCIIPopTab(viewer)); 1803 } 1804 } 1805 DMPlexTransform tr; 1806 1807 PetscCall(DMPlexGetTransform(dm, &tr)); 1808 if (tr) { 1809 PetscCall(PetscViewerASCIIPushTab(viewer)); 1810 PetscCall(PetscViewerASCIIPrintf(viewer, "Created using transform:\n")); 1811 PetscCall(DMPlexTransformView(tr, viewer)); 1812 PetscCall(PetscViewerASCIIPopTab(viewer)); 1813 } 1814 PetscCall(DMGetCoarseDM(dm, &cdm)); 1815 if (cdm) { 1816 PetscCall(PetscViewerASCIIPushTab(viewer)); 1817 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1818 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1819 PetscCall(PetscViewerASCIIPopTab(viewer)); 1820 } 1821 } 1822 PetscFunctionReturn(PETSC_SUCCESS); 1823 } 1824 1825 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1826 { 1827 DMPolytopeType ct; 1828 PetscMPIInt rank; 1829 PetscInt cdim; 1830 1831 PetscFunctionBegin; 1832 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1833 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1834 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1835 switch (ct) { 1836 case DM_POLYTOPE_SEGMENT: 1837 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1838 switch (cdim) { 1839 case 1: { 1840 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1841 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1842 1843 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1844 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1845 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1846 } break; 1847 case 2: { 1848 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1849 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1850 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1851 1852 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1853 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1854 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1855 } break; 1856 default: 1857 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1858 } 1859 break; 1860 case DM_POLYTOPE_TRIANGLE: 1861 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1862 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1863 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1864 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1865 break; 1866 case DM_POLYTOPE_QUADRILATERAL: 1867 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1868 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1869 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1870 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1871 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1872 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1873 break; 1874 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1875 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1876 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1877 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1878 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1879 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1880 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1881 break; 1882 case DM_POLYTOPE_FV_GHOST: 1883 break; 1884 default: 1885 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1886 } 1887 PetscFunctionReturn(PETSC_SUCCESS); 1888 } 1889 1890 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1891 { 1892 PetscReal centroid[2] = {0., 0.}; 1893 PetscMPIInt rank; 1894 PetscMPIInt fillColor; 1895 1896 PetscFunctionBegin; 1897 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1898 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1899 for (PetscInt v = 0; v < Nv; ++v) { 1900 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1901 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1902 } 1903 for (PetscInt e = 0; e < Nv; ++e) { 1904 refCoords[0] = refVertices[e * 2 + 0]; 1905 refCoords[1] = refVertices[e * 2 + 1]; 1906 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1907 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1908 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1909 } 1910 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1911 for (PetscInt d = 0; d < edgeDiv; ++d) { 1912 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)); 1913 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1914 } 1915 } 1916 PetscFunctionReturn(PETSC_SUCCESS); 1917 } 1918 1919 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1920 { 1921 DMPolytopeType ct; 1922 1923 PetscFunctionBegin; 1924 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1925 switch (ct) { 1926 case DM_POLYTOPE_TRIANGLE: { 1927 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1928 1929 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1930 } break; 1931 case DM_POLYTOPE_QUADRILATERAL: { 1932 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1933 1934 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1935 } break; 1936 default: 1937 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1938 } 1939 PetscFunctionReturn(PETSC_SUCCESS); 1940 } 1941 1942 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1943 { 1944 PetscDraw draw; 1945 DM cdm; 1946 PetscSection coordSection; 1947 Vec coordinates; 1948 PetscReal xyl[3], xyr[3]; 1949 PetscReal *refCoords, *edgeCoords; 1950 PetscBool isnull, drawAffine; 1951 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1952 1953 PetscFunctionBegin; 1954 PetscCall(DMGetCoordinateDim(dm, &dim)); 1955 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1956 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1957 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1958 edgeDiv = cDegree + 1; 1959 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1960 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1961 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1962 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1963 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1964 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1965 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1966 1967 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1968 PetscCall(PetscDrawIsNull(draw, &isnull)); 1969 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1970 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1971 1972 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1973 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1974 PetscCall(PetscDrawClear(draw)); 1975 1976 for (c = cStart; c < cEnd; ++c) { 1977 PetscScalar *coords = NULL; 1978 const PetscScalar *coords_arr; 1979 PetscInt numCoords; 1980 PetscBool isDG; 1981 1982 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1983 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1984 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1985 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1986 } 1987 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1988 PetscCall(PetscDrawFlush(draw)); 1989 PetscCall(PetscDrawPause(draw)); 1990 PetscCall(PetscDrawSave(draw)); 1991 PetscFunctionReturn(PETSC_SUCCESS); 1992 } 1993 1994 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1995 { 1996 DM odm = dm, rdm = dm, cdm; 1997 PetscFE fe; 1998 PetscSpace sp; 1999 PetscClassId id; 2000 PetscInt degree; 2001 PetscBool hoView = PETSC_TRUE; 2002 2003 PetscFunctionBegin; 2004 PetscObjectOptionsBegin((PetscObject)dm); 2005 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 2006 PetscOptionsEnd(); 2007 PetscCall(PetscObjectReference((PetscObject)dm)); 2008 *hdm = dm; 2009 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 2010 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2011 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 2012 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 2013 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 2014 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 2015 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 2016 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 2017 DM cdm, rcdm; 2018 Mat In; 2019 Vec cl, rcl; 2020 2021 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 2022 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 2023 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 2024 PetscCall(DMGetCoordinateDM(odm, &cdm)); 2025 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 2026 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 2027 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 2028 PetscCall(DMSetCoarseDM(rcdm, cdm)); 2029 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 2030 PetscCall(MatMult(In, cl, rcl)); 2031 PetscCall(MatDestroy(&In)); 2032 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 2033 PetscCall(DMDestroy(&odm)); 2034 odm = rdm; 2035 } 2036 *hdm = rdm; 2037 PetscFunctionReturn(PETSC_SUCCESS); 2038 } 2039 2040 #if defined(PETSC_HAVE_EXODUSII) 2041 #include <exodusII.h> 2042 #include <petscviewerexodusii.h> 2043 #endif 2044 2045 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 2046 { 2047 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 2048 char name[PETSC_MAX_PATH_LEN]; 2049 2050 PetscFunctionBegin; 2051 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2052 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2053 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 2054 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2055 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2056 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2057 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 2058 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 2059 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 2060 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2061 if (iascii) { 2062 PetscViewerFormat format; 2063 PetscCall(PetscViewerGetFormat(viewer, &format)); 2064 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 2065 else PetscCall(DMPlexView_Ascii(dm, viewer)); 2066 } else if (ishdf5) { 2067 #if defined(PETSC_HAVE_HDF5) 2068 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 2069 #else 2070 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2071 #endif 2072 } else if (isvtk) { 2073 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2074 } else if (isdraw) { 2075 DM hdm; 2076 2077 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2078 PetscCall(DMPlexView_Draw(hdm, viewer)); 2079 PetscCall(DMDestroy(&hdm)); 2080 } else if (isglvis) { 2081 PetscCall(DMPlexView_GLVis(dm, viewer)); 2082 #if defined(PETSC_HAVE_EXODUSII) 2083 } else if (isexodus) { 2084 /* 2085 exodusII requires that all sets be part of exactly one cell set. 2086 If the dm does not have a "Cell Sets" label defined, we create one 2087 with ID 1, containing all cells. 2088 Note that if the Cell Sets label is defined but does not cover all cells, 2089 we may still have a problem. This should probably be checked here or in the viewer; 2090 */ 2091 PetscInt numCS; 2092 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2093 if (!numCS) { 2094 PetscInt cStart, cEnd, c; 2095 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2096 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2097 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2098 } 2099 PetscCall(DMView_PlexExodusII(dm, viewer)); 2100 #endif 2101 #if defined(PETSC_HAVE_CGNS) 2102 } else if (iscgns) { 2103 PetscCall(DMView_PlexCGNS(dm, viewer)); 2104 #endif 2105 } else if (ispython) { 2106 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2107 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2108 /* Optionally view the partition */ 2109 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2110 if (flg) { 2111 Vec ranks; 2112 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2113 PetscCall(VecView(ranks, viewer)); 2114 PetscCall(VecDestroy(&ranks)); 2115 } 2116 /* Optionally view a label */ 2117 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2118 if (flg) { 2119 DMLabel label; 2120 Vec val; 2121 2122 PetscCall(DMGetLabel(dm, name, &label)); 2123 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2124 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2125 PetscCall(VecView(val, viewer)); 2126 PetscCall(VecDestroy(&val)); 2127 } 2128 PetscFunctionReturn(PETSC_SUCCESS); 2129 } 2130 2131 /*@ 2132 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2133 2134 Collective 2135 2136 Input Parameters: 2137 + dm - The `DM` whose topology is to be saved 2138 - viewer - The `PetscViewer` to save it in 2139 2140 Level: advanced 2141 2142 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2143 @*/ 2144 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2145 { 2146 PetscBool ishdf5; 2147 2148 PetscFunctionBegin; 2149 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2150 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2151 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2152 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2153 if (ishdf5) { 2154 #if defined(PETSC_HAVE_HDF5) 2155 PetscViewerFormat format; 2156 PetscCall(PetscViewerGetFormat(viewer, &format)); 2157 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2158 IS globalPointNumbering; 2159 2160 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2161 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2162 PetscCall(ISDestroy(&globalPointNumbering)); 2163 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 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 PetscCall(PetscViewerGetFormat(viewer, &format)); 2198 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2199 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2200 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 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 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2238 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2239 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2240 PetscCall(ISDestroy(&globalPointNumbering)); 2241 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2242 #else 2243 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2244 #endif 2245 } 2246 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2247 PetscFunctionReturn(PETSC_SUCCESS); 2248 } 2249 2250 /*@ 2251 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2252 2253 Collective 2254 2255 Input Parameters: 2256 + dm - The `DM` that contains the topology on which the section to be saved is defined 2257 . viewer - The `PetscViewer` for saving 2258 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2259 2260 Level: advanced 2261 2262 Notes: 2263 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. 2264 2265 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. 2266 2267 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2268 @*/ 2269 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2270 { 2271 PetscBool ishdf5; 2272 2273 PetscFunctionBegin; 2274 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2275 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2276 if (!sectiondm) sectiondm = dm; 2277 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2278 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2279 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2280 if (ishdf5) { 2281 #if defined(PETSC_HAVE_HDF5) 2282 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2283 #else 2284 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2285 #endif 2286 } 2287 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2288 PetscFunctionReturn(PETSC_SUCCESS); 2289 } 2290 2291 /*@ 2292 DMPlexGlobalVectorView - Saves a global vector 2293 2294 Collective 2295 2296 Input Parameters: 2297 + dm - The `DM` that represents the topology 2298 . viewer - The `PetscViewer` to save data with 2299 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2300 - vec - The global vector to be saved 2301 2302 Level: advanced 2303 2304 Notes: 2305 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. 2306 2307 Calling sequence: 2308 .vb 2309 DMCreate(PETSC_COMM_WORLD, &dm); 2310 DMSetType(dm, DMPLEX); 2311 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2312 DMClone(dm, §iondm); 2313 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2314 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2315 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2316 PetscSectionSetChart(section, pStart, pEnd); 2317 PetscSectionSetUp(section); 2318 DMSetLocalSection(sectiondm, section); 2319 PetscSectionDestroy(§ion); 2320 DMGetGlobalVector(sectiondm, &vec); 2321 PetscObjectSetName((PetscObject)vec, "vec_name"); 2322 DMPlexTopologyView(dm, viewer); 2323 DMPlexSectionView(dm, viewer, sectiondm); 2324 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2325 DMRestoreGlobalVector(sectiondm, &vec); 2326 DMDestroy(§iondm); 2327 DMDestroy(&dm); 2328 .ve 2329 2330 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2331 @*/ 2332 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2333 { 2334 PetscBool ishdf5; 2335 2336 PetscFunctionBegin; 2337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2338 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2339 if (!sectiondm) sectiondm = dm; 2340 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2341 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2342 /* Check consistency */ 2343 { 2344 PetscSection section; 2345 PetscBool includesConstraints; 2346 PetscInt m, m1; 2347 2348 PetscCall(VecGetLocalSize(vec, &m1)); 2349 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2350 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2351 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2352 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2353 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2354 } 2355 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2356 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2357 if (ishdf5) { 2358 #if defined(PETSC_HAVE_HDF5) 2359 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2360 #else 2361 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2362 #endif 2363 } 2364 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2365 PetscFunctionReturn(PETSC_SUCCESS); 2366 } 2367 2368 /*@ 2369 DMPlexLocalVectorView - Saves a local vector 2370 2371 Collective 2372 2373 Input Parameters: 2374 + dm - The `DM` that represents the topology 2375 . viewer - The `PetscViewer` to save data with 2376 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2377 - vec - The local vector to be saved 2378 2379 Level: advanced 2380 2381 Note: 2382 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. 2383 2384 Calling sequence: 2385 .vb 2386 DMCreate(PETSC_COMM_WORLD, &dm); 2387 DMSetType(dm, DMPLEX); 2388 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2389 DMClone(dm, §iondm); 2390 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2391 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2392 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2393 PetscSectionSetChart(section, pStart, pEnd); 2394 PetscSectionSetUp(section); 2395 DMSetLocalSection(sectiondm, section); 2396 DMGetLocalVector(sectiondm, &vec); 2397 PetscObjectSetName((PetscObject)vec, "vec_name"); 2398 DMPlexTopologyView(dm, viewer); 2399 DMPlexSectionView(dm, viewer, sectiondm); 2400 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2401 DMRestoreLocalVector(sectiondm, &vec); 2402 DMDestroy(§iondm); 2403 DMDestroy(&dm); 2404 .ve 2405 2406 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2407 @*/ 2408 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2409 { 2410 PetscBool ishdf5; 2411 2412 PetscFunctionBegin; 2413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2414 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2415 if (!sectiondm) sectiondm = dm; 2416 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2417 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2418 /* Check consistency */ 2419 { 2420 PetscSection section; 2421 PetscBool includesConstraints; 2422 PetscInt m, m1; 2423 2424 PetscCall(VecGetLocalSize(vec, &m1)); 2425 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2426 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2427 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2428 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2429 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2430 } 2431 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2432 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2433 if (ishdf5) { 2434 #if defined(PETSC_HAVE_HDF5) 2435 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2436 #else 2437 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2438 #endif 2439 } 2440 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2441 PetscFunctionReturn(PETSC_SUCCESS); 2442 } 2443 2444 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2445 { 2446 PetscBool ishdf5; 2447 2448 PetscFunctionBegin; 2449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2450 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2451 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2452 if (ishdf5) { 2453 #if defined(PETSC_HAVE_HDF5) 2454 PetscViewerFormat format; 2455 PetscCall(PetscViewerGetFormat(viewer, &format)); 2456 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2457 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2458 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2459 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2460 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2461 PetscFunctionReturn(PETSC_SUCCESS); 2462 #else 2463 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2464 #endif 2465 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2466 } 2467 2468 /*@ 2469 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2470 2471 Collective 2472 2473 Input Parameters: 2474 + dm - The `DM` into which the topology is loaded 2475 - viewer - The `PetscViewer` for the saved topology 2476 2477 Output Parameter: 2478 . 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; 2479 `NULL` if unneeded 2480 2481 Level: advanced 2482 2483 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2484 `PetscViewer`, `PetscSF` 2485 @*/ 2486 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2487 { 2488 PetscBool ishdf5; 2489 2490 PetscFunctionBegin; 2491 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2492 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2493 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2494 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2495 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2496 if (ishdf5) { 2497 #if defined(PETSC_HAVE_HDF5) 2498 PetscViewerFormat format; 2499 PetscCall(PetscViewerGetFormat(viewer, &format)); 2500 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2501 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2502 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2503 #else 2504 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2505 #endif 2506 } 2507 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2508 PetscFunctionReturn(PETSC_SUCCESS); 2509 } 2510 2511 /*@ 2512 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2513 2514 Collective 2515 2516 Input Parameters: 2517 + dm - The `DM` into which the coordinates are loaded 2518 . viewer - The `PetscViewer` for the saved coordinates 2519 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2520 2521 Level: advanced 2522 2523 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2524 `PetscSF`, `PetscViewer` 2525 @*/ 2526 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2527 { 2528 PetscBool ishdf5; 2529 2530 PetscFunctionBegin; 2531 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2532 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2533 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2534 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2535 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2536 if (ishdf5) { 2537 #if defined(PETSC_HAVE_HDF5) 2538 PetscViewerFormat format; 2539 PetscCall(PetscViewerGetFormat(viewer, &format)); 2540 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2541 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2542 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2543 #else 2544 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2545 #endif 2546 } 2547 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2548 PetscFunctionReturn(PETSC_SUCCESS); 2549 } 2550 2551 /*@ 2552 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2553 2554 Collective 2555 2556 Input Parameters: 2557 + dm - The `DM` into which the labels are loaded 2558 . viewer - The `PetscViewer` for the saved labels 2559 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2560 2561 Level: advanced 2562 2563 Note: 2564 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2565 2566 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2567 `PetscSF`, `PetscViewer` 2568 @*/ 2569 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2570 { 2571 PetscBool ishdf5; 2572 2573 PetscFunctionBegin; 2574 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2575 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2576 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2577 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2578 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2579 if (ishdf5) { 2580 #if defined(PETSC_HAVE_HDF5) 2581 PetscViewerFormat format; 2582 2583 PetscCall(PetscViewerGetFormat(viewer, &format)); 2584 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2585 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2586 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2587 #else 2588 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2589 #endif 2590 } 2591 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2592 PetscFunctionReturn(PETSC_SUCCESS); 2593 } 2594 2595 /*@ 2596 DMPlexSectionLoad - Loads section into a `DMPLEX` 2597 2598 Collective 2599 2600 Input Parameters: 2601 + dm - The `DM` that represents the topology 2602 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2603 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2604 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2605 2606 Output Parameters: 2607 + 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) 2608 - 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) 2609 2610 Level: advanced 2611 2612 Notes: 2613 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. 2614 2615 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. 2616 2617 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. 2618 2619 Example using 2 processes: 2620 .vb 2621 NX (number of points on dm): 4 2622 sectionA : the on-disk section 2623 vecA : a vector associated with sectionA 2624 sectionB : sectiondm's local section constructed in this function 2625 vecB (local) : a vector associated with sectiondm's local section 2626 vecB (global) : a vector associated with sectiondm's global section 2627 2628 rank 0 rank 1 2629 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2630 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2631 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2632 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2633 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2634 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2635 sectionB->atlasDof : 1 0 1 | 1 3 2636 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2637 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2638 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2639 .ve 2640 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2641 2642 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2643 @*/ 2644 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, PeOp DM sectiondm, PetscSF globalToLocalPointSF, PeOp PetscSF *globalDofSF, PeOp PetscSF *localDofSF) 2645 { 2646 PetscBool ishdf5; 2647 2648 PetscFunctionBegin; 2649 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2650 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2651 if (!sectiondm) sectiondm = dm; 2652 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2653 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2654 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2655 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2656 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2657 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2658 if (ishdf5) { 2659 #if defined(PETSC_HAVE_HDF5) 2660 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2661 #else 2662 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2663 #endif 2664 } 2665 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2666 PetscFunctionReturn(PETSC_SUCCESS); 2667 } 2668 2669 /*@ 2670 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2671 2672 Collective 2673 2674 Input Parameters: 2675 + dm - The `DM` that represents the topology 2676 . viewer - The `PetscViewer` that represents the on-disk vector data 2677 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2678 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2679 - vec - The global vector to set values of 2680 2681 Level: advanced 2682 2683 Notes: 2684 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. 2685 2686 Calling sequence: 2687 .vb 2688 DMCreate(PETSC_COMM_WORLD, &dm); 2689 DMSetType(dm, DMPLEX); 2690 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2691 DMPlexTopologyLoad(dm, viewer, &sfX); 2692 DMClone(dm, §iondm); 2693 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2694 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2695 DMGetGlobalVector(sectiondm, &vec); 2696 PetscObjectSetName((PetscObject)vec, "vec_name"); 2697 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2698 DMRestoreGlobalVector(sectiondm, &vec); 2699 PetscSFDestroy(&gsf); 2700 PetscSFDestroy(&sfX); 2701 DMDestroy(§iondm); 2702 DMDestroy(&dm); 2703 .ve 2704 2705 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2706 `PetscSF`, `PetscViewer` 2707 @*/ 2708 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2709 { 2710 PetscBool ishdf5; 2711 2712 PetscFunctionBegin; 2713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2714 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2715 if (!sectiondm) sectiondm = dm; 2716 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2717 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2718 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2719 /* Check consistency */ 2720 { 2721 PetscSection section; 2722 PetscBool includesConstraints; 2723 PetscInt m, m1; 2724 2725 PetscCall(VecGetLocalSize(vec, &m1)); 2726 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2727 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2728 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2729 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2730 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2731 } 2732 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2733 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2734 if (ishdf5) { 2735 #if defined(PETSC_HAVE_HDF5) 2736 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2737 #else 2738 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2739 #endif 2740 } 2741 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2742 PetscFunctionReturn(PETSC_SUCCESS); 2743 } 2744 2745 /*@ 2746 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2747 2748 Collective 2749 2750 Input Parameters: 2751 + dm - The `DM` that represents the topology 2752 . viewer - The `PetscViewer` that represents the on-disk vector data 2753 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2754 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2755 - vec - The local vector to set values of 2756 2757 Level: advanced 2758 2759 Notes: 2760 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. 2761 2762 Calling sequence: 2763 .vb 2764 DMCreate(PETSC_COMM_WORLD, &dm); 2765 DMSetType(dm, DMPLEX); 2766 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2767 DMPlexTopologyLoad(dm, viewer, &sfX); 2768 DMClone(dm, §iondm); 2769 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2770 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2771 DMGetLocalVector(sectiondm, &vec); 2772 PetscObjectSetName((PetscObject)vec, "vec_name"); 2773 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2774 DMRestoreLocalVector(sectiondm, &vec); 2775 PetscSFDestroy(&lsf); 2776 PetscSFDestroy(&sfX); 2777 DMDestroy(§iondm); 2778 DMDestroy(&dm); 2779 .ve 2780 2781 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2782 `PetscSF`, `PetscViewer` 2783 @*/ 2784 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2785 { 2786 PetscBool ishdf5; 2787 2788 PetscFunctionBegin; 2789 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2790 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2791 if (!sectiondm) sectiondm = dm; 2792 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2793 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2794 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2795 /* Check consistency */ 2796 { 2797 PetscSection section; 2798 PetscBool includesConstraints; 2799 PetscInt m, m1; 2800 2801 PetscCall(VecGetLocalSize(vec, &m1)); 2802 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2803 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2804 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2805 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2806 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2807 } 2808 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2809 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2810 if (ishdf5) { 2811 #if defined(PETSC_HAVE_HDF5) 2812 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2813 #else 2814 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2815 #endif 2816 } 2817 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2818 PetscFunctionReturn(PETSC_SUCCESS); 2819 } 2820 2821 PetscErrorCode DMDestroy_Plex(DM dm) 2822 { 2823 DM_Plex *mesh = (DM_Plex *)dm->data; 2824 2825 PetscFunctionBegin; 2826 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2827 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2828 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2829 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBounds_C", NULL)); 2830 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2831 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2832 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2833 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2834 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2835 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2836 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2837 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2838 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2839 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2840 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2841 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2842 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2843 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2844 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2845 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2846 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2847 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2848 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2849 PetscCall(PetscFree(mesh->cones)); 2850 PetscCall(PetscFree(mesh->coneOrientations)); 2851 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2852 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2853 PetscCall(PetscFree(mesh->supports)); 2854 PetscCall(PetscFree(mesh->cellTypes)); 2855 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2856 PetscCall(PetscFree(mesh->tetgenOpts)); 2857 PetscCall(PetscFree(mesh->triangleOpts)); 2858 PetscCall(PetscFree(mesh->transformType)); 2859 PetscCall(PetscFree(mesh->distributionName)); 2860 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2861 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2862 PetscCall(ISDestroy(&mesh->subpointIS)); 2863 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2864 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2865 if (mesh->periodic.face_sfs) { 2866 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2867 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2868 } 2869 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2870 if (mesh->periodic.periodic_points) { 2871 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2872 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2873 } 2874 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2875 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2876 PetscCall(ISDestroy(&mesh->anchorIS)); 2877 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2878 PetscCall(PetscFree(mesh->parents)); 2879 PetscCall(PetscFree(mesh->childIDs)); 2880 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2881 PetscCall(PetscFree(mesh->children)); 2882 PetscCall(DMDestroy(&mesh->referenceTree)); 2883 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2884 PetscCall(PetscFree(mesh->neighbors)); 2885 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2886 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2887 PetscCall(DMPlexTransformDestroy(&mesh->transform)); 2888 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2889 PetscCall(PetscFree(mesh)); 2890 PetscFunctionReturn(PETSC_SUCCESS); 2891 } 2892 2893 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2894 { 2895 PetscSection sectionGlobal, sectionLocal; 2896 PetscInt bs = -1, mbs; 2897 PetscInt localSize, localStart = 0; 2898 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2899 MatType mtype; 2900 ISLocalToGlobalMapping ltog; 2901 2902 PetscFunctionBegin; 2903 PetscCall(MatInitializePackage()); 2904 mtype = dm->mattype; 2905 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2906 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2907 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2908 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2909 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2910 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2911 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2912 PetscCall(MatSetType(*J, mtype)); 2913 PetscCall(MatSetFromOptions(*J)); 2914 PetscCall(MatGetBlockSize(*J, &mbs)); 2915 if (mbs > 1) bs = mbs; 2916 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2917 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2918 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2919 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2920 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2921 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2922 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2923 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2924 if (!isShell) { 2925 // There are three states with pblocks, since block starts can have no dofs: 2926 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2927 // TRUE) Block Start: The first entry in a block has been added 2928 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2929 PetscBT blst; 2930 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2931 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2932 const PetscInt *perm = NULL; 2933 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2934 PetscInt pStart, pEnd, dof, cdof, num_fields; 2935 2936 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2937 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2938 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2939 2940 PetscCall(PetscCalloc1(localSize, &pblocks)); 2941 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2942 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2943 // We need to process in the permuted order to get block sizes right 2944 for (PetscInt point = pStart; point < pEnd; ++point) { 2945 const PetscInt p = perm ? perm[point] : point; 2946 2947 switch (dm->blocking_type) { 2948 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2949 PetscInt bdof, offset; 2950 2951 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2952 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2953 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2954 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2955 if (dof > 0) { 2956 // State change 2957 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2958 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2959 2960 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2961 // Signal block concatenation 2962 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2963 } 2964 dof = dof < 0 ? -(dof + 1) : dof; 2965 bdof = cdof && (dof - cdof) ? 1 : dof; 2966 if (dof) { 2967 if (bs < 0) { 2968 bs = bdof; 2969 } else if (bs != bdof) { 2970 bs = 1; 2971 } 2972 } 2973 } break; 2974 case DM_BLOCKING_FIELD_NODE: { 2975 for (PetscInt field = 0; field < num_fields; field++) { 2976 PetscInt num_comp, bdof, offset; 2977 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2978 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2979 if (dof < 0) continue; 2980 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2981 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2982 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); 2983 PetscInt num_nodes = dof / num_comp; 2984 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2985 // Handle possibly constant block size (unlikely) 2986 bdof = cdof && (dof - cdof) ? 1 : dof; 2987 if (dof) { 2988 if (bs < 0) { 2989 bs = bdof; 2990 } else if (bs != bdof) { 2991 bs = 1; 2992 } 2993 } 2994 } 2995 } break; 2996 } 2997 } 2998 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2999 /* Must have same blocksize on all procs (some might have no points) */ 3000 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 3001 bsLocal[1] = bs; 3002 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 3003 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 3004 else bs = bsMinMax[0]; 3005 bs = PetscMax(1, bs); 3006 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 3007 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 3008 PetscCall(MatSetBlockSize(*J, bs)); 3009 PetscCall(MatSetUp(*J)); 3010 } else { 3011 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 3012 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 3013 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 3014 } 3015 if (pblocks) { // Consolidate blocks 3016 PetscInt nblocks = 0; 3017 pblocks[0] = PetscAbs(pblocks[0]); 3018 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 3019 if (pblocks[i] == 0) continue; 3020 // Negative block size indicates the blocks should be concatenated 3021 if (pblocks[i] < 0) { 3022 pblocks[i] = -pblocks[i]; 3023 pblocks[nblocks - 1] += pblocks[i]; 3024 } else { 3025 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 3026 } 3027 for (PetscInt j = 1; j < pblocks[i]; j++) 3028 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); 3029 } 3030 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 3031 } 3032 PetscCall(PetscFree(pblocks)); 3033 } 3034 PetscCall(MatSetDM(*J, dm)); 3035 PetscFunctionReturn(PETSC_SUCCESS); 3036 } 3037 3038 /*@ 3039 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 3040 3041 Not Collective 3042 3043 Input Parameter: 3044 . dm - The `DMPLEX` 3045 3046 Output Parameter: 3047 . subsection - The subdomain section 3048 3049 Level: developer 3050 3051 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 3052 @*/ 3053 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 3054 { 3055 DM_Plex *mesh = (DM_Plex *)dm->data; 3056 3057 PetscFunctionBegin; 3058 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3059 if (!mesh->subdomainSection) { 3060 PetscSection section; 3061 PetscSF sf; 3062 3063 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 3064 PetscCall(DMGetLocalSection(dm, §ion)); 3065 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 3066 PetscCall(PetscSFDestroy(&sf)); 3067 } 3068 *subsection = mesh->subdomainSection; 3069 PetscFunctionReturn(PETSC_SUCCESS); 3070 } 3071 3072 /*@ 3073 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 3074 3075 Not Collective 3076 3077 Input Parameter: 3078 . dm - The `DMPLEX` 3079 3080 Output Parameters: 3081 + pStart - The first mesh point 3082 - pEnd - The upper bound for mesh points 3083 3084 Level: beginner 3085 3086 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3087 @*/ 3088 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3089 { 3090 DM_Plex *mesh = (DM_Plex *)dm->data; 3091 3092 PetscFunctionBegin; 3093 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3094 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3095 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3096 PetscFunctionReturn(PETSC_SUCCESS); 3097 } 3098 3099 /*@ 3100 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3101 3102 Not Collective 3103 3104 Input Parameters: 3105 + dm - The `DMPLEX` 3106 . pStart - The first mesh point 3107 - pEnd - The upper bound for mesh points 3108 3109 Level: beginner 3110 3111 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3112 @*/ 3113 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3114 { 3115 DM_Plex *mesh = (DM_Plex *)dm->data; 3116 3117 PetscFunctionBegin; 3118 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3119 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3120 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3121 PetscCall(PetscFree(mesh->cellTypes)); 3122 PetscFunctionReturn(PETSC_SUCCESS); 3123 } 3124 3125 /*@ 3126 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3127 3128 Not Collective 3129 3130 Input Parameters: 3131 + dm - The `DMPLEX` 3132 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3133 3134 Output Parameter: 3135 . size - The cone size for point `p` 3136 3137 Level: beginner 3138 3139 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3140 @*/ 3141 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3142 { 3143 DM_Plex *mesh = (DM_Plex *)dm->data; 3144 3145 PetscFunctionBegin; 3146 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3147 PetscAssertPointer(size, 3); 3148 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3149 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3150 PetscFunctionReturn(PETSC_SUCCESS); 3151 } 3152 3153 /*@ 3154 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3155 3156 Not Collective 3157 3158 Input Parameters: 3159 + dm - The `DMPLEX` 3160 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3161 - size - The cone size for point `p` 3162 3163 Level: beginner 3164 3165 Note: 3166 This should be called after `DMPlexSetChart()`. 3167 3168 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3169 @*/ 3170 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3171 { 3172 DM_Plex *mesh = (DM_Plex *)dm->data; 3173 3174 PetscFunctionBegin; 3175 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3176 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3177 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3178 PetscFunctionReturn(PETSC_SUCCESS); 3179 } 3180 3181 /*@C 3182 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3183 3184 Not Collective 3185 3186 Input Parameters: 3187 + dm - The `DMPLEX` 3188 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3189 3190 Output Parameter: 3191 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3192 3193 Level: beginner 3194 3195 Fortran Notes: 3196 `cone` must be declared with 3197 .vb 3198 PetscInt, pointer :: cone(:) 3199 .ve 3200 3201 You must call `DMPlexRestoreCone()` after you finish using the array. 3202 `DMPlexRestoreCone()` is not needed/available in C. 3203 3204 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3205 @*/ 3206 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3207 { 3208 DM_Plex *mesh = (DM_Plex *)dm->data; 3209 PetscInt off; 3210 3211 PetscFunctionBegin; 3212 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3213 PetscAssertPointer(cone, 3); 3214 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3215 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3216 PetscFunctionReturn(PETSC_SUCCESS); 3217 } 3218 3219 /*@ 3220 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3221 3222 Not Collective 3223 3224 Input Parameters: 3225 + dm - The `DMPLEX` 3226 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3227 3228 Output Parameters: 3229 + pConesSection - `PetscSection` describing the layout of `pCones` 3230 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3231 3232 Level: intermediate 3233 3234 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3235 @*/ 3236 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PeOp PetscSection *pConesSection, PeOp IS *pCones) 3237 { 3238 PetscSection cs, newcs; 3239 PetscInt *cones; 3240 PetscInt *newarr = NULL; 3241 PetscInt n; 3242 3243 PetscFunctionBegin; 3244 PetscCall(DMPlexGetCones(dm, &cones)); 3245 PetscCall(DMPlexGetConeSection(dm, &cs)); 3246 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3247 if (pConesSection) *pConesSection = newcs; 3248 if (pCones) { 3249 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3250 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3251 } 3252 PetscFunctionReturn(PETSC_SUCCESS); 3253 } 3254 3255 /*@ 3256 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3257 3258 Not Collective 3259 3260 Input Parameters: 3261 + dm - The `DMPLEX` 3262 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3263 3264 Output Parameter: 3265 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3266 3267 Level: advanced 3268 3269 Notes: 3270 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3271 3272 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3273 3274 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3275 `DMPlexGetDepth()`, `IS` 3276 @*/ 3277 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3278 { 3279 IS *expandedPointsAll; 3280 PetscInt depth; 3281 3282 PetscFunctionBegin; 3283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3284 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3285 PetscAssertPointer(expandedPoints, 3); 3286 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3287 *expandedPoints = expandedPointsAll[0]; 3288 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3289 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3290 PetscFunctionReturn(PETSC_SUCCESS); 3291 } 3292 3293 /*@ 3294 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3295 (DAG points of depth 0, i.e., without cones). 3296 3297 Not Collective 3298 3299 Input Parameters: 3300 + dm - The `DMPLEX` 3301 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3302 3303 Output Parameters: 3304 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3305 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3306 - sections - (optional) An array of sections which describe mappings from points to their cone points 3307 3308 Level: advanced 3309 3310 Notes: 3311 Like `DMPlexGetConeTuple()` but recursive. 3312 3313 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. 3314 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3315 3316 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\: 3317 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3318 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3319 3320 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3321 `DMPlexGetDepth()`, `PetscSection`, `IS` 3322 @*/ 3323 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3324 { 3325 const PetscInt *arr0 = NULL, *cone = NULL; 3326 PetscInt *arr = NULL, *newarr = NULL; 3327 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3328 IS *expandedPoints_; 3329 PetscSection *sections_; 3330 3331 PetscFunctionBegin; 3332 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3333 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3334 if (depth) PetscAssertPointer(depth, 3); 3335 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3336 if (sections) PetscAssertPointer(sections, 5); 3337 PetscCall(ISGetLocalSize(points, &n)); 3338 PetscCall(ISGetIndices(points, &arr0)); 3339 PetscCall(DMPlexGetDepth(dm, &depth_)); 3340 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3341 PetscCall(PetscCalloc1(depth_, §ions_)); 3342 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3343 for (d = depth_ - 1; d >= 0; d--) { 3344 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3345 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3346 for (i = 0; i < n; i++) { 3347 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3348 if (arr[i] >= start && arr[i] < end) { 3349 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3350 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3351 } else { 3352 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3353 } 3354 } 3355 PetscCall(PetscSectionSetUp(sections_[d])); 3356 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3357 PetscCall(PetscMalloc1(newn, &newarr)); 3358 for (i = 0; i < n; i++) { 3359 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3360 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3361 if (cn > 1) { 3362 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3363 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3364 } else { 3365 newarr[co] = arr[i]; 3366 } 3367 } 3368 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3369 arr = newarr; 3370 n = newn; 3371 } 3372 PetscCall(ISRestoreIndices(points, &arr0)); 3373 *depth = depth_; 3374 if (expandedPoints) *expandedPoints = expandedPoints_; 3375 else { 3376 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3377 PetscCall(PetscFree(expandedPoints_)); 3378 } 3379 if (sections) *sections = sections_; 3380 else { 3381 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3382 PetscCall(PetscFree(sections_)); 3383 } 3384 PetscFunctionReturn(PETSC_SUCCESS); 3385 } 3386 3387 /*@ 3388 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3389 3390 Not Collective 3391 3392 Input Parameters: 3393 + dm - The `DMPLEX` 3394 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3395 3396 Output Parameters: 3397 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3398 . expandedPoints - (optional) An array of recursively expanded cones 3399 - sections - (optional) An array of sections which describe mappings from points to their cone points 3400 3401 Level: advanced 3402 3403 Note: 3404 See `DMPlexGetConeRecursive()` 3405 3406 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3407 `DMPlexGetDepth()`, `IS`, `PetscSection` 3408 @*/ 3409 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3410 { 3411 PetscInt d, depth_; 3412 3413 PetscFunctionBegin; 3414 PetscCall(DMPlexGetDepth(dm, &depth_)); 3415 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3416 if (depth) *depth = 0; 3417 if (expandedPoints) { 3418 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3419 PetscCall(PetscFree(*expandedPoints)); 3420 } 3421 if (sections) { 3422 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3423 PetscCall(PetscFree(*sections)); 3424 } 3425 PetscFunctionReturn(PETSC_SUCCESS); 3426 } 3427 3428 /*@ 3429 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 3430 3431 Not Collective 3432 3433 Input Parameters: 3434 + dm - The `DMPLEX` 3435 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3436 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3437 3438 Level: beginner 3439 3440 Note: 3441 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3442 3443 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3444 @*/ 3445 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3446 { 3447 DM_Plex *mesh = (DM_Plex *)dm->data; 3448 PetscInt dof, off, c; 3449 3450 PetscFunctionBegin; 3451 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3452 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3453 if (dof) PetscAssertPointer(cone, 3); 3454 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3455 if (PetscDefined(USE_DEBUG)) { 3456 PetscInt pStart, pEnd; 3457 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3458 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); 3459 for (c = 0; c < dof; ++c) { 3460 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); 3461 mesh->cones[off + c] = cone[c]; 3462 } 3463 } else { 3464 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3465 } 3466 PetscFunctionReturn(PETSC_SUCCESS); 3467 } 3468 3469 /*@C 3470 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3471 3472 Not Collective 3473 3474 Input Parameters: 3475 + dm - The `DMPLEX` 3476 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3477 3478 Output Parameter: 3479 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3480 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3481 3482 Level: beginner 3483 3484 Note: 3485 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3486 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3487 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3488 with the identity. 3489 3490 Fortran Notes: 3491 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3492 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3493 3494 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3495 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3496 @*/ 3497 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3498 { 3499 DM_Plex *mesh = (DM_Plex *)dm->data; 3500 PetscInt off; 3501 3502 PetscFunctionBegin; 3503 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3504 if (PetscDefined(USE_DEBUG)) { 3505 PetscInt dof; 3506 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3507 if (dof) PetscAssertPointer(coneOrientation, 3); 3508 } 3509 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3510 3511 *coneOrientation = &mesh->coneOrientations[off]; 3512 PetscFunctionReturn(PETSC_SUCCESS); 3513 } 3514 3515 /*@ 3516 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3517 3518 Not Collective 3519 3520 Input Parameters: 3521 + dm - The `DMPLEX` 3522 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3523 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3524 3525 Level: beginner 3526 3527 Notes: 3528 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3529 3530 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3531 3532 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3533 @*/ 3534 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3535 { 3536 DM_Plex *mesh = (DM_Plex *)dm->data; 3537 PetscInt pStart, pEnd; 3538 PetscInt dof, off, c; 3539 3540 PetscFunctionBegin; 3541 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3542 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3543 if (dof) PetscAssertPointer(coneOrientation, 3); 3544 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3545 if (PetscDefined(USE_DEBUG)) { 3546 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3547 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); 3548 for (c = 0; c < dof; ++c) { 3549 PetscInt cdof, o = coneOrientation[c]; 3550 3551 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3552 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); 3553 mesh->coneOrientations[off + c] = o; 3554 } 3555 } else { 3556 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3557 } 3558 PetscFunctionReturn(PETSC_SUCCESS); 3559 } 3560 3561 /*@ 3562 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3563 3564 Not Collective 3565 3566 Input Parameters: 3567 + dm - The `DMPLEX` 3568 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3569 . conePos - The local index in the cone where the point should be put 3570 - conePoint - The mesh point to insert 3571 3572 Level: beginner 3573 3574 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3575 @*/ 3576 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3577 { 3578 DM_Plex *mesh = (DM_Plex *)dm->data; 3579 PetscInt pStart, pEnd; 3580 PetscInt dof, off; 3581 3582 PetscFunctionBegin; 3583 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3584 if (PetscDefined(USE_DEBUG)) { 3585 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3586 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); 3587 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); 3588 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3589 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); 3590 } 3591 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3592 mesh->cones[off + conePos] = conePoint; 3593 PetscFunctionReturn(PETSC_SUCCESS); 3594 } 3595 3596 /*@ 3597 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3598 3599 Not Collective 3600 3601 Input Parameters: 3602 + dm - The `DMPLEX` 3603 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3604 . conePos - The local index in the cone where the point should be put 3605 - coneOrientation - The point orientation to insert 3606 3607 Level: beginner 3608 3609 Note: 3610 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3611 3612 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3613 @*/ 3614 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3615 { 3616 DM_Plex *mesh = (DM_Plex *)dm->data; 3617 PetscInt pStart, pEnd; 3618 PetscInt dof, off; 3619 3620 PetscFunctionBegin; 3621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3622 if (PetscDefined(USE_DEBUG)) { 3623 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3624 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); 3625 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3626 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); 3627 } 3628 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3629 mesh->coneOrientations[off + conePos] = coneOrientation; 3630 PetscFunctionReturn(PETSC_SUCCESS); 3631 } 3632 3633 /*@C 3634 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3635 3636 Not collective 3637 3638 Input Parameters: 3639 + dm - The DMPlex 3640 - p - The point, which must lie in the chart set with DMPlexSetChart() 3641 3642 Output Parameters: 3643 + cone - An array of points which are on the in-edges for point `p` 3644 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3645 integer giving the prescription for cone traversal. 3646 3647 Level: beginner 3648 3649 Notes: 3650 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3651 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3652 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3653 with the identity. 3654 3655 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3656 3657 Fortran Notes: 3658 `cone` and `ornt` must be declared with 3659 .vb 3660 PetscInt, pointer :: cone(:) 3661 PetscInt, pointer :: ornt(:) 3662 .ve 3663 3664 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3665 @*/ 3666 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, PeOp const PetscInt *cone[], PeOp const PetscInt *ornt[]) 3667 { 3668 DM_Plex *mesh = (DM_Plex *)dm->data; 3669 3670 PetscFunctionBegin; 3671 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3672 if (mesh->tr) { 3673 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3674 } else { 3675 PetscInt off; 3676 if (PetscDefined(USE_DEBUG)) { 3677 PetscInt dof; 3678 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3679 if (dof) { 3680 if (cone) PetscAssertPointer(cone, 3); 3681 if (ornt) PetscAssertPointer(ornt, 4); 3682 } 3683 } 3684 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3685 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3686 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3687 } 3688 PetscFunctionReturn(PETSC_SUCCESS); 3689 } 3690 3691 /*@C 3692 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3693 3694 Not Collective 3695 3696 Input Parameters: 3697 + dm - The DMPlex 3698 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3699 . cone - An array of points which are on the in-edges for point p 3700 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3701 integer giving the prescription for cone traversal. 3702 3703 Level: beginner 3704 3705 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3706 @*/ 3707 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3708 { 3709 DM_Plex *mesh = (DM_Plex *)dm->data; 3710 3711 PetscFunctionBegin; 3712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3713 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3714 PetscFunctionReturn(PETSC_SUCCESS); 3715 } 3716 3717 /*@ 3718 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3719 3720 Not Collective 3721 3722 Input Parameters: 3723 + dm - The `DMPLEX` 3724 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3725 3726 Output Parameter: 3727 . size - The support size for point `p` 3728 3729 Level: beginner 3730 3731 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3732 @*/ 3733 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3734 { 3735 DM_Plex *mesh = (DM_Plex *)dm->data; 3736 3737 PetscFunctionBegin; 3738 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3739 PetscAssertPointer(size, 3); 3740 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3741 PetscFunctionReturn(PETSC_SUCCESS); 3742 } 3743 3744 /*@ 3745 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3746 3747 Not Collective 3748 3749 Input Parameters: 3750 + dm - The `DMPLEX` 3751 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3752 - size - The support size for point `p` 3753 3754 Level: beginner 3755 3756 Note: 3757 This should be called after `DMPlexSetChart()`. 3758 3759 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3760 @*/ 3761 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3762 { 3763 DM_Plex *mesh = (DM_Plex *)dm->data; 3764 3765 PetscFunctionBegin; 3766 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3767 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3768 PetscFunctionReturn(PETSC_SUCCESS); 3769 } 3770 3771 /*@C 3772 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3773 3774 Not Collective 3775 3776 Input Parameters: 3777 + dm - The `DMPLEX` 3778 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3779 3780 Output Parameter: 3781 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3782 3783 Level: beginner 3784 3785 Fortran Notes: 3786 `support` must be declared with 3787 .vb 3788 PetscInt, pointer :: support(:) 3789 .ve 3790 3791 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3792 `DMPlexRestoreSupport()` is not needed/available in C. 3793 3794 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3795 @*/ 3796 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3797 { 3798 DM_Plex *mesh = (DM_Plex *)dm->data; 3799 PetscInt off; 3800 3801 PetscFunctionBegin; 3802 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3803 PetscAssertPointer(support, 3); 3804 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3805 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3806 PetscFunctionReturn(PETSC_SUCCESS); 3807 } 3808 3809 /*@ 3810 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3811 3812 Not Collective 3813 3814 Input Parameters: 3815 + dm - The `DMPLEX` 3816 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3817 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3818 3819 Level: beginner 3820 3821 Note: 3822 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3823 3824 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3825 @*/ 3826 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3827 { 3828 DM_Plex *mesh = (DM_Plex *)dm->data; 3829 PetscInt pStart, pEnd; 3830 PetscInt dof, off, c; 3831 3832 PetscFunctionBegin; 3833 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3834 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3835 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3836 if (dof) PetscAssertPointer(support, 3); 3837 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3838 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); 3839 for (c = 0; c < dof; ++c) { 3840 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); 3841 mesh->supports[off + c] = support[c]; 3842 } 3843 PetscFunctionReturn(PETSC_SUCCESS); 3844 } 3845 3846 /*@ 3847 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3848 3849 Not Collective 3850 3851 Input Parameters: 3852 + dm - The `DMPLEX` 3853 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3854 . supportPos - The local index in the cone where the point should be put 3855 - supportPoint - The mesh point to insert 3856 3857 Level: beginner 3858 3859 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3860 @*/ 3861 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3862 { 3863 DM_Plex *mesh = (DM_Plex *)dm->data; 3864 PetscInt pStart, pEnd; 3865 PetscInt dof, off; 3866 3867 PetscFunctionBegin; 3868 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3869 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3870 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3871 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3872 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); 3873 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); 3874 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); 3875 mesh->supports[off + supportPos] = supportPoint; 3876 PetscFunctionReturn(PETSC_SUCCESS); 3877 } 3878 3879 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3880 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3881 { 3882 switch (ct) { 3883 case DM_POLYTOPE_SEGMENT: 3884 if (o == -1) return -2; 3885 break; 3886 case DM_POLYTOPE_TRIANGLE: 3887 if (o == -3) return -1; 3888 if (o == -2) return -3; 3889 if (o == -1) return -2; 3890 break; 3891 case DM_POLYTOPE_QUADRILATERAL: 3892 if (o == -4) return -2; 3893 if (o == -3) return -1; 3894 if (o == -2) return -4; 3895 if (o == -1) return -3; 3896 break; 3897 default: 3898 return o; 3899 } 3900 return o; 3901 } 3902 3903 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3904 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3905 { 3906 switch (ct) { 3907 case DM_POLYTOPE_SEGMENT: 3908 if ((o == -2) || (o == 1)) return -1; 3909 if (o == -1) return 0; 3910 break; 3911 case DM_POLYTOPE_TRIANGLE: 3912 if (o == -3) return -2; 3913 if (o == -2) return -1; 3914 if (o == -1) return -3; 3915 break; 3916 case DM_POLYTOPE_QUADRILATERAL: 3917 if (o == -4) return -2; 3918 if (o == -3) return -1; 3919 if (o == -2) return -4; 3920 if (o == -1) return -3; 3921 break; 3922 default: 3923 return o; 3924 } 3925 return o; 3926 } 3927 3928 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3929 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3930 { 3931 PetscInt pStart, pEnd, p; 3932 3933 PetscFunctionBegin; 3934 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3935 for (p = pStart; p < pEnd; ++p) { 3936 const PetscInt *cone, *ornt; 3937 PetscInt coneSize, c; 3938 3939 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3940 PetscCall(DMPlexGetCone(dm, p, &cone)); 3941 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3942 for (c = 0; c < coneSize; ++c) { 3943 DMPolytopeType ct; 3944 const PetscInt o = ornt[c]; 3945 3946 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3947 switch (ct) { 3948 case DM_POLYTOPE_SEGMENT: 3949 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3950 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3951 break; 3952 case DM_POLYTOPE_TRIANGLE: 3953 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3954 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3955 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3956 break; 3957 case DM_POLYTOPE_QUADRILATERAL: 3958 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3959 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3960 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3961 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3962 break; 3963 default: 3964 break; 3965 } 3966 } 3967 } 3968 PetscFunctionReturn(PETSC_SUCCESS); 3969 } 3970 3971 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3972 { 3973 DM_Plex *mesh = (DM_Plex *)dm->data; 3974 3975 PetscFunctionBeginHot; 3976 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3977 if (useCone) { 3978 PetscCall(DMPlexGetConeSize(dm, p, size)); 3979 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3980 } else { 3981 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3982 PetscCall(DMPlexGetSupport(dm, p, arr)); 3983 } 3984 } else { 3985 if (useCone) { 3986 const PetscSection s = mesh->coneSection; 3987 const PetscInt ps = p - s->pStart; 3988 const PetscInt off = s->atlasOff[ps]; 3989 3990 *size = s->atlasDof[ps]; 3991 *arr = mesh->cones + off; 3992 *ornt = mesh->coneOrientations + off; 3993 } else { 3994 const PetscSection s = mesh->supportSection; 3995 const PetscInt ps = p - s->pStart; 3996 const PetscInt off = s->atlasOff[ps]; 3997 3998 *size = s->atlasDof[ps]; 3999 *arr = mesh->supports + off; 4000 } 4001 } 4002 PetscFunctionReturn(PETSC_SUCCESS); 4003 } 4004 4005 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 4006 { 4007 DM_Plex *mesh = (DM_Plex *)dm->data; 4008 4009 PetscFunctionBeginHot; 4010 if (PetscDefined(USE_DEBUG) || mesh->tr) { 4011 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 4012 } 4013 PetscFunctionReturn(PETSC_SUCCESS); 4014 } 4015 4016 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4017 { 4018 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4019 PetscInt *closure; 4020 const PetscInt *tmp = NULL, *tmpO = NULL; 4021 PetscInt off = 0, tmpSize, t; 4022 4023 PetscFunctionBeginHot; 4024 if (ornt) { 4025 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4026 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; 4027 } 4028 if (*points) { 4029 closure = *points; 4030 } else { 4031 PetscInt maxConeSize, maxSupportSize; 4032 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4033 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 4034 } 4035 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4036 if (ct == DM_POLYTOPE_UNKNOWN) { 4037 closure[off++] = p; 4038 closure[off++] = 0; 4039 for (t = 0; t < tmpSize; ++t) { 4040 closure[off++] = tmp[t]; 4041 closure[off++] = tmpO ? tmpO[t] : 0; 4042 } 4043 } else { 4044 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 4045 4046 /* We assume that cells with a valid type have faces with a valid type */ 4047 closure[off++] = p; 4048 closure[off++] = ornt; 4049 for (t = 0; t < tmpSize; ++t) { 4050 DMPolytopeType ft; 4051 4052 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 4053 closure[off++] = tmp[arr[t]]; 4054 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 4055 } 4056 } 4057 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4058 if (numPoints) *numPoints = tmpSize + 1; 4059 if (points) *points = closure; 4060 PetscFunctionReturn(PETSC_SUCCESS); 4061 } 4062 4063 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 4064 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 4065 { 4066 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 4067 const PetscInt *cone, *ornt; 4068 PetscInt *pts, *closure = NULL; 4069 DMPolytopeType ft; 4070 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 4071 PetscInt dim, coneSize, c, d, clSize, cl; 4072 4073 PetscFunctionBeginHot; 4074 PetscCall(DMGetDimension(dm, &dim)); 4075 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4076 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4077 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4078 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4079 maxSize = PetscMax(coneSeries, supportSeries); 4080 if (*points) { 4081 pts = *points; 4082 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4083 c = 0; 4084 pts[c++] = point; 4085 pts[c++] = o; 4086 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4087 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4088 for (cl = 0; cl < clSize * 2; cl += 2) { 4089 pts[c++] = closure[cl]; 4090 pts[c++] = closure[cl + 1]; 4091 } 4092 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4093 for (cl = 0; cl < clSize * 2; cl += 2) { 4094 pts[c++] = closure[cl]; 4095 pts[c++] = closure[cl + 1]; 4096 } 4097 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4098 for (d = 2; d < coneSize; ++d) { 4099 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4100 pts[c++] = cone[arr[d * 2 + 0]]; 4101 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4102 } 4103 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4104 if (dim >= 3) { 4105 for (d = 2; d < coneSize; ++d) { 4106 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4107 const PetscInt *fcone, *fornt; 4108 PetscInt fconeSize, fc, i; 4109 4110 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4111 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4112 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4113 for (fc = 0; fc < fconeSize; ++fc) { 4114 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4115 const PetscInt co = farr[fc * 2 + 1]; 4116 4117 for (i = 0; i < c; i += 2) 4118 if (pts[i] == cp) break; 4119 if (i == c) { 4120 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4121 pts[c++] = cp; 4122 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4123 } 4124 } 4125 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4126 } 4127 } 4128 *numPoints = c / 2; 4129 *points = pts; 4130 PetscFunctionReturn(PETSC_SUCCESS); 4131 } 4132 4133 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4134 { 4135 DMPolytopeType ct; 4136 PetscInt *closure, *fifo; 4137 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4138 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4139 PetscInt depth, maxSize; 4140 4141 PetscFunctionBeginHot; 4142 PetscCall(DMPlexGetDepth(dm, &depth)); 4143 if (depth == 1) { 4144 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4145 PetscFunctionReturn(PETSC_SUCCESS); 4146 } 4147 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4148 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; 4149 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4150 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4151 PetscFunctionReturn(PETSC_SUCCESS); 4152 } 4153 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4154 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4155 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4156 maxSize = PetscMax(coneSeries, supportSeries); 4157 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4158 if (*points) { 4159 closure = *points; 4160 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4161 closure[closureSize++] = p; 4162 closure[closureSize++] = ornt; 4163 fifo[fifoSize++] = p; 4164 fifo[fifoSize++] = ornt; 4165 fifo[fifoSize++] = ct; 4166 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4167 while (fifoSize - fifoStart) { 4168 const PetscInt q = fifo[fifoStart++]; 4169 const PetscInt o = fifo[fifoStart++]; 4170 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4171 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4172 const PetscInt *tmp, *tmpO = NULL; 4173 PetscInt tmpSize, t; 4174 4175 if (PetscDefined(USE_DEBUG)) { 4176 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4177 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); 4178 } 4179 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4180 for (t = 0; t < tmpSize; ++t) { 4181 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4182 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4183 const PetscInt cp = tmp[ip]; 4184 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4185 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4186 PetscInt c; 4187 4188 /* Check for duplicate */ 4189 for (c = 0; c < closureSize; c += 2) { 4190 if (closure[c] == cp) break; 4191 } 4192 if (c == closureSize) { 4193 closure[closureSize++] = cp; 4194 closure[closureSize++] = co; 4195 fifo[fifoSize++] = cp; 4196 fifo[fifoSize++] = co; 4197 fifo[fifoSize++] = ct; 4198 } 4199 } 4200 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4201 } 4202 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4203 if (numPoints) *numPoints = closureSize / 2; 4204 if (points) *points = closure; 4205 PetscFunctionReturn(PETSC_SUCCESS); 4206 } 4207 4208 /*@C 4209 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4210 4211 Not Collective 4212 4213 Input Parameters: 4214 + dm - The `DMPLEX` 4215 . p - The mesh point 4216 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4217 4218 Input/Output Parameter: 4219 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4220 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4221 otherwise the provided array is used to hold the values 4222 4223 Output Parameter: 4224 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4225 4226 Level: beginner 4227 4228 Note: 4229 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4230 4231 Fortran Notes: 4232 `points` must be declared with 4233 .vb 4234 PetscInt, pointer :: points(:) 4235 .ve 4236 and is always allocated by the function. 4237 4238 Pass `PETSC_NULL_INTEGER` for `numPoints` if it is not needed 4239 4240 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4241 @*/ 4242 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4243 { 4244 PetscFunctionBeginHot; 4245 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4246 if (numPoints) PetscAssertPointer(numPoints, 4); 4247 if (points) PetscAssertPointer(points, 5); 4248 if (PetscDefined(USE_DEBUG)) { 4249 PetscInt pStart, pEnd; 4250 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4251 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); 4252 } 4253 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4254 PetscFunctionReturn(PETSC_SUCCESS); 4255 } 4256 4257 /*@C 4258 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4259 4260 Not Collective 4261 4262 Input Parameters: 4263 + dm - The `DMPLEX` 4264 . p - The mesh point 4265 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4266 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4267 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4268 4269 Level: beginner 4270 4271 Note: 4272 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4273 4274 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4275 @*/ 4276 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4277 { 4278 PetscFunctionBeginHot; 4279 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4280 if (numPoints) *numPoints = 0; 4281 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4282 PetscFunctionReturn(PETSC_SUCCESS); 4283 } 4284 4285 /*@ 4286 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4287 4288 Not Collective 4289 4290 Input Parameter: 4291 . dm - The `DMPLEX` 4292 4293 Output Parameters: 4294 + maxConeSize - The maximum number of in-edges 4295 - maxSupportSize - The maximum number of out-edges 4296 4297 Level: beginner 4298 4299 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4300 @*/ 4301 PetscErrorCode DMPlexGetMaxSizes(DM dm, PeOp PetscInt *maxConeSize, PeOp PetscInt *maxSupportSize) 4302 { 4303 DM_Plex *mesh = (DM_Plex *)dm->data; 4304 4305 PetscFunctionBegin; 4306 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4307 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4308 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4309 PetscFunctionReturn(PETSC_SUCCESS); 4310 } 4311 4312 PetscErrorCode DMSetUp_Plex(DM dm) 4313 { 4314 DM_Plex *mesh = (DM_Plex *)dm->data; 4315 PetscInt size, maxSupportSize; 4316 4317 PetscFunctionBegin; 4318 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4319 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4320 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4321 PetscCall(PetscMalloc1(size, &mesh->cones)); 4322 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4323 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4324 if (maxSupportSize) { 4325 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4326 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4327 PetscCall(PetscMalloc1(size, &mesh->supports)); 4328 } 4329 PetscFunctionReturn(PETSC_SUCCESS); 4330 } 4331 4332 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4333 { 4334 PetscFunctionBegin; 4335 if (subdm) PetscCall(DMClone(dm, subdm)); 4336 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4337 if (subdm) (*subdm)->useNatural = dm->useNatural; 4338 if (dm->useNatural && dm->sfMigration) { 4339 PetscSF sfNatural; 4340 4341 (*subdm)->sfMigration = dm->sfMigration; 4342 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4343 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4344 (*subdm)->sfNatural = sfNatural; 4345 } 4346 PetscFunctionReturn(PETSC_SUCCESS); 4347 } 4348 4349 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4350 { 4351 PetscInt i = 0; 4352 4353 PetscFunctionBegin; 4354 PetscCall(DMClone(dms[0], superdm)); 4355 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4356 (*superdm)->useNatural = PETSC_FALSE; 4357 for (i = 0; i < len; i++) { 4358 if (dms[i]->useNatural && dms[i]->sfMigration) { 4359 PetscSF sfNatural; 4360 4361 (*superdm)->sfMigration = dms[i]->sfMigration; 4362 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4363 (*superdm)->useNatural = PETSC_TRUE; 4364 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4365 (*superdm)->sfNatural = sfNatural; 4366 break; 4367 } 4368 } 4369 PetscFunctionReturn(PETSC_SUCCESS); 4370 } 4371 4372 /*@ 4373 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4374 4375 Not Collective 4376 4377 Input Parameter: 4378 . dm - The `DMPLEX` 4379 4380 Level: beginner 4381 4382 Note: 4383 This should be called after all calls to `DMPlexSetCone()` 4384 4385 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4386 @*/ 4387 PetscErrorCode DMPlexSymmetrize(DM dm) 4388 { 4389 DM_Plex *mesh = (DM_Plex *)dm->data; 4390 PetscInt *offsets; 4391 PetscInt supportSize; 4392 PetscInt pStart, pEnd, p; 4393 4394 PetscFunctionBegin; 4395 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4396 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4397 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4398 /* Calculate support sizes */ 4399 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4400 for (p = pStart; p < pEnd; ++p) { 4401 PetscInt dof, off, c; 4402 4403 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4404 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4405 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4406 } 4407 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4408 /* Calculate supports */ 4409 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4410 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4411 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4412 for (p = pStart; p < pEnd; ++p) { 4413 PetscInt dof, off, c; 4414 4415 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4416 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4417 for (c = off; c < off + dof; ++c) { 4418 const PetscInt q = mesh->cones[c]; 4419 PetscInt offS; 4420 4421 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4422 4423 mesh->supports[offS + offsets[q]] = p; 4424 ++offsets[q]; 4425 } 4426 } 4427 PetscCall(PetscFree(offsets)); 4428 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4429 PetscFunctionReturn(PETSC_SUCCESS); 4430 } 4431 4432 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4433 { 4434 IS stratumIS; 4435 4436 PetscFunctionBegin; 4437 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4438 if (PetscDefined(USE_DEBUG)) { 4439 PetscInt qStart, qEnd, numLevels, level; 4440 PetscBool overlap = PETSC_FALSE; 4441 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4442 for (level = 0; level < numLevels; level++) { 4443 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4444 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4445 overlap = PETSC_TRUE; 4446 break; 4447 } 4448 } 4449 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); 4450 } 4451 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4452 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4453 PetscCall(ISDestroy(&stratumIS)); 4454 PetscFunctionReturn(PETSC_SUCCESS); 4455 } 4456 4457 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4458 { 4459 PetscInt *pMin, *pMax; 4460 PetscInt pStart, pEnd; 4461 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4462 4463 PetscFunctionBegin; 4464 { 4465 DMLabel label2; 4466 4467 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4468 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4469 } 4470 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4471 for (PetscInt p = pStart; p < pEnd; ++p) { 4472 DMPolytopeType ct; 4473 4474 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4475 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4476 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4477 } 4478 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4479 for (PetscInt d = dmin; d <= dmax; ++d) { 4480 pMin[d] = PETSC_INT_MAX; 4481 pMax[d] = PETSC_INT_MIN; 4482 } 4483 for (PetscInt p = pStart; p < pEnd; ++p) { 4484 DMPolytopeType ct; 4485 PetscInt d; 4486 4487 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4488 d = DMPolytopeTypeGetDim(ct); 4489 pMin[d] = PetscMin(p, pMin[d]); 4490 pMax[d] = PetscMax(p, pMax[d]); 4491 } 4492 for (PetscInt d = dmin; d <= dmax; ++d) { 4493 if (pMin[d] > pMax[d]) continue; 4494 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4495 } 4496 PetscCall(PetscFree2(pMin, pMax)); 4497 PetscFunctionReturn(PETSC_SUCCESS); 4498 } 4499 4500 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4501 { 4502 PetscInt pStart, pEnd; 4503 PetscInt numRoots = 0, numLeaves = 0; 4504 4505 PetscFunctionBegin; 4506 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4507 { 4508 /* Initialize roots and count leaves */ 4509 PetscInt sMin = PETSC_INT_MAX; 4510 PetscInt sMax = PETSC_INT_MIN; 4511 PetscInt coneSize, supportSize; 4512 4513 for (PetscInt p = pStart; p < pEnd; ++p) { 4514 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4515 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4516 if (!coneSize && supportSize) { 4517 sMin = PetscMin(p, sMin); 4518 sMax = PetscMax(p, sMax); 4519 ++numRoots; 4520 } else if (!supportSize && coneSize) { 4521 ++numLeaves; 4522 } else if (!supportSize && !coneSize) { 4523 /* Isolated points */ 4524 sMin = PetscMin(p, sMin); 4525 sMax = PetscMax(p, sMax); 4526 } 4527 } 4528 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4529 } 4530 4531 if (numRoots + numLeaves == (pEnd - pStart)) { 4532 PetscInt sMin = PETSC_INT_MAX; 4533 PetscInt sMax = PETSC_INT_MIN; 4534 PetscInt coneSize, supportSize; 4535 4536 for (PetscInt p = pStart; p < pEnd; ++p) { 4537 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4538 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4539 if (!supportSize && coneSize) { 4540 sMin = PetscMin(p, sMin); 4541 sMax = PetscMax(p, sMax); 4542 } 4543 } 4544 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4545 } else { 4546 PetscInt level = 0; 4547 PetscInt qStart, qEnd; 4548 4549 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4550 while (qEnd > qStart) { 4551 PetscInt sMin = PETSC_INT_MAX; 4552 PetscInt sMax = PETSC_INT_MIN; 4553 4554 for (PetscInt q = qStart; q < qEnd; ++q) { 4555 const PetscInt *support; 4556 PetscInt supportSize; 4557 4558 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4559 PetscCall(DMPlexGetSupport(dm, q, &support)); 4560 for (PetscInt s = 0; s < supportSize; ++s) { 4561 sMin = PetscMin(support[s], sMin); 4562 sMax = PetscMax(support[s], sMax); 4563 } 4564 } 4565 PetscCall(DMLabelGetNumValues(label, &level)); 4566 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4567 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4568 } 4569 } 4570 PetscFunctionReturn(PETSC_SUCCESS); 4571 } 4572 4573 /*@ 4574 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4575 4576 Collective 4577 4578 Input Parameter: 4579 . dm - The `DMPLEX` 4580 4581 Level: beginner 4582 4583 Notes: 4584 The strata group all points of the same grade, and this function calculates the strata. This 4585 grade can be seen as the height (or depth) of the point in the DAG. 4586 4587 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4588 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4589 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4590 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4591 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4592 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4593 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4594 4595 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4596 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4597 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 4598 to interpolate only that one (e0), so that 4599 .vb 4600 cone(c0) = {e0, v2} 4601 cone(e0) = {v0, v1} 4602 .ve 4603 If `DMPlexStratify()` is run on this mesh, it will give depths 4604 .vb 4605 depth 0 = {v0, v1, v2} 4606 depth 1 = {e0, c0} 4607 .ve 4608 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4609 4610 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4611 4612 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4613 @*/ 4614 PetscErrorCode DMPlexStratify(DM dm) 4615 { 4616 DM_Plex *mesh = (DM_Plex *)dm->data; 4617 DMLabel label; 4618 PetscBool flg = PETSC_FALSE; 4619 4620 PetscFunctionBegin; 4621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4622 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4623 4624 // Create depth label 4625 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4626 PetscCall(DMCreateLabel(dm, "depth")); 4627 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4628 4629 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4630 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4631 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4632 4633 { /* just in case there is an empty process */ 4634 PetscInt numValues, maxValues = 0, v; 4635 4636 PetscCall(DMLabelGetNumValues(label, &numValues)); 4637 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4638 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4639 } 4640 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4641 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4642 PetscFunctionReturn(PETSC_SUCCESS); 4643 } 4644 4645 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4646 { 4647 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4648 PetscInt dim, depth, pheight, coneSize; 4649 PetscBool preferTensor; 4650 4651 PetscFunctionBeginHot; 4652 PetscCall(DMGetDimension(dm, &dim)); 4653 PetscCall(DMPlexGetDepth(dm, &depth)); 4654 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4655 PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor)); 4656 pheight = depth - pdepth; 4657 if (depth <= 1) { 4658 switch (pdepth) { 4659 case 0: 4660 ct = DM_POLYTOPE_POINT; 4661 break; 4662 case 1: 4663 switch (coneSize) { 4664 case 2: 4665 ct = DM_POLYTOPE_SEGMENT; 4666 break; 4667 case 3: 4668 ct = DM_POLYTOPE_TRIANGLE; 4669 break; 4670 case 4: 4671 switch (dim) { 4672 case 2: 4673 ct = DM_POLYTOPE_QUADRILATERAL; 4674 break; 4675 case 3: 4676 ct = DM_POLYTOPE_TETRAHEDRON; 4677 break; 4678 default: 4679 break; 4680 } 4681 break; 4682 case 5: 4683 ct = DM_POLYTOPE_PYRAMID; 4684 break; 4685 case 6: 4686 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4687 break; 4688 case 8: 4689 ct = DM_POLYTOPE_HEXAHEDRON; 4690 break; 4691 default: 4692 break; 4693 } 4694 } 4695 } else { 4696 if (pdepth == 0) { 4697 ct = DM_POLYTOPE_POINT; 4698 } else if (pheight == 0) { 4699 switch (dim) { 4700 case 1: 4701 switch (coneSize) { 4702 case 2: 4703 ct = DM_POLYTOPE_SEGMENT; 4704 break; 4705 default: 4706 break; 4707 } 4708 break; 4709 case 2: 4710 switch (coneSize) { 4711 case 3: 4712 ct = DM_POLYTOPE_TRIANGLE; 4713 break; 4714 case 4: 4715 ct = DM_POLYTOPE_QUADRILATERAL; 4716 break; 4717 default: 4718 break; 4719 } 4720 break; 4721 case 3: 4722 switch (coneSize) { 4723 case 4: 4724 ct = DM_POLYTOPE_TETRAHEDRON; 4725 break; 4726 case 5: { 4727 const PetscInt *cone; 4728 PetscInt faceConeSize; 4729 4730 PetscCall(DMPlexGetCone(dm, p, &cone)); 4731 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4732 switch (faceConeSize) { 4733 case 3: 4734 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4735 break; 4736 case 4: 4737 ct = DM_POLYTOPE_PYRAMID; 4738 break; 4739 } 4740 } break; 4741 case 6: 4742 ct = DM_POLYTOPE_HEXAHEDRON; 4743 break; 4744 default: 4745 break; 4746 } 4747 break; 4748 default: 4749 break; 4750 } 4751 } else if (pheight > 0) { 4752 switch (coneSize) { 4753 case 2: 4754 ct = DM_POLYTOPE_SEGMENT; 4755 break; 4756 case 3: 4757 ct = DM_POLYTOPE_TRIANGLE; 4758 break; 4759 case 4: 4760 ct = DM_POLYTOPE_QUADRILATERAL; 4761 break; 4762 default: 4763 break; 4764 } 4765 } 4766 } 4767 *pt = ct; 4768 PetscFunctionReturn(PETSC_SUCCESS); 4769 } 4770 4771 /*@ 4772 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4773 4774 Collective 4775 4776 Input Parameter: 4777 . dm - The `DMPLEX` 4778 4779 Level: developer 4780 4781 Note: 4782 This function is normally called automatically when a cell type is requested. It creates an 4783 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4784 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4785 4786 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4787 4788 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4789 @*/ 4790 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4791 { 4792 DM_Plex *mesh; 4793 DMLabel ctLabel; 4794 PetscInt pStart, pEnd, p; 4795 4796 PetscFunctionBegin; 4797 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4798 mesh = (DM_Plex *)dm->data; 4799 PetscCall(DMCreateLabel(dm, "celltype")); 4800 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4801 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4802 PetscCall(PetscFree(mesh->cellTypes)); 4803 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4804 for (p = pStart; p < pEnd; ++p) { 4805 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4806 PetscInt pdepth; 4807 4808 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4809 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4810 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]); 4811 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4812 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4813 } 4814 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4815 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4816 PetscFunctionReturn(PETSC_SUCCESS); 4817 } 4818 4819 /*@C 4820 DMPlexGetJoin - Get an array for the join of the set of points 4821 4822 Not Collective 4823 4824 Input Parameters: 4825 + dm - The `DMPLEX` object 4826 . numPoints - The number of input points for the join 4827 - points - The input points 4828 4829 Output Parameters: 4830 + numCoveredPoints - The number of points in the join 4831 - coveredPoints - The points in the join 4832 4833 Level: intermediate 4834 4835 Note: 4836 Currently, this is restricted to a single level join 4837 4838 Fortran Notes: 4839 `converedPoints` must be declared with 4840 .vb 4841 PetscInt, pointer :: coveredPints(:) 4842 .ve 4843 4844 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4845 @*/ 4846 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4847 { 4848 DM_Plex *mesh = (DM_Plex *)dm->data; 4849 PetscInt *join[2]; 4850 PetscInt joinSize, i = 0; 4851 PetscInt dof, off, p, c, m; 4852 PetscInt maxSupportSize; 4853 4854 PetscFunctionBegin; 4855 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4856 PetscAssertPointer(points, 3); 4857 PetscAssertPointer(numCoveredPoints, 4); 4858 PetscAssertPointer(coveredPoints, 5); 4859 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4860 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4861 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4862 /* Copy in support of first point */ 4863 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4864 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4865 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4866 /* Check each successive support */ 4867 for (p = 1; p < numPoints; ++p) { 4868 PetscInt newJoinSize = 0; 4869 4870 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4871 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4872 for (c = 0; c < dof; ++c) { 4873 const PetscInt point = mesh->supports[off + c]; 4874 4875 for (m = 0; m < joinSize; ++m) { 4876 if (point == join[i][m]) { 4877 join[1 - i][newJoinSize++] = point; 4878 break; 4879 } 4880 } 4881 } 4882 joinSize = newJoinSize; 4883 i = 1 - i; 4884 } 4885 *numCoveredPoints = joinSize; 4886 *coveredPoints = join[i]; 4887 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4888 PetscFunctionReturn(PETSC_SUCCESS); 4889 } 4890 4891 /*@C 4892 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4893 4894 Not Collective 4895 4896 Input Parameters: 4897 + dm - The `DMPLEX` object 4898 . numPoints - The number of input points for the join 4899 - points - The input points 4900 4901 Output Parameters: 4902 + numCoveredPoints - The number of points in the join 4903 - coveredPoints - The points in the join 4904 4905 Level: intermediate 4906 4907 Fortran Notes: 4908 `converedPoints` must be declared with 4909 .vb 4910 PetscInt, pointer :: coveredPoints(:) 4911 .ve 4912 4913 Pass `PETSC_NULL_INTEGER` for `numCoveredPoints` if it is not needed 4914 4915 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4916 @*/ 4917 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4918 { 4919 PetscFunctionBegin; 4920 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4921 if (points) PetscAssertPointer(points, 3); 4922 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4923 PetscAssertPointer(coveredPoints, 5); 4924 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4925 if (numCoveredPoints) *numCoveredPoints = 0; 4926 PetscFunctionReturn(PETSC_SUCCESS); 4927 } 4928 4929 /*@C 4930 DMPlexGetFullJoin - Get an array for the join of the set of points 4931 4932 Not Collective 4933 4934 Input Parameters: 4935 + dm - The `DMPLEX` object 4936 . numPoints - The number of input points for the join 4937 - points - The input points, its length is `numPoints` 4938 4939 Output Parameters: 4940 + numCoveredPoints - The number of points in the join 4941 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4942 4943 Level: intermediate 4944 4945 Fortran Notes: 4946 .vb 4947 PetscInt, pointer :: coveredPints(:) 4948 .ve 4949 4950 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4951 @*/ 4952 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4953 { 4954 PetscInt *offsets, **closures; 4955 PetscInt *join[2]; 4956 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4957 PetscInt p, d, c, m, ms; 4958 4959 PetscFunctionBegin; 4960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4961 PetscAssertPointer(points, 3); 4962 PetscAssertPointer(numCoveredPoints, 4); 4963 PetscAssertPointer(coveredPoints, 5); 4964 4965 PetscCall(DMPlexGetDepth(dm, &depth)); 4966 PetscCall(PetscCalloc1(numPoints, &closures)); 4967 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4968 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4969 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4970 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4971 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4972 4973 for (p = 0; p < numPoints; ++p) { 4974 PetscInt closureSize; 4975 4976 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4977 4978 offsets[p * (depth + 2) + 0] = 0; 4979 for (d = 0; d < depth + 1; ++d) { 4980 PetscInt pStart, pEnd, i; 4981 4982 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4983 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4984 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4985 offsets[p * (depth + 2) + d + 1] = i; 4986 break; 4987 } 4988 } 4989 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4990 } 4991 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); 4992 } 4993 for (d = 0; d < depth + 1; ++d) { 4994 PetscInt dof; 4995 4996 /* Copy in support of first point */ 4997 dof = offsets[d + 1] - offsets[d]; 4998 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4999 /* Check each successive cone */ 5000 for (p = 1; p < numPoints && joinSize; ++p) { 5001 PetscInt newJoinSize = 0; 5002 5003 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 5004 for (c = 0; c < dof; ++c) { 5005 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 5006 5007 for (m = 0; m < joinSize; ++m) { 5008 if (point == join[i][m]) { 5009 join[1 - i][newJoinSize++] = point; 5010 break; 5011 } 5012 } 5013 } 5014 joinSize = newJoinSize; 5015 i = 1 - i; 5016 } 5017 if (joinSize) break; 5018 } 5019 *numCoveredPoints = joinSize; 5020 *coveredPoints = join[i]; 5021 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 5022 PetscCall(PetscFree(closures)); 5023 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 5024 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 5025 PetscFunctionReturn(PETSC_SUCCESS); 5026 } 5027 5028 /*@C 5029 DMPlexGetMeet - Get an array for the meet of the set of points 5030 5031 Not Collective 5032 5033 Input Parameters: 5034 + dm - The `DMPLEX` object 5035 . numPoints - The number of input points for the meet 5036 - points - The input points, of length `numPoints` 5037 5038 Output Parameters: 5039 + numCoveringPoints - The number of points in the meet 5040 - coveringPoints - The points in the meet, of length `numCoveringPoints` 5041 5042 Level: intermediate 5043 5044 Note: 5045 Currently, this is restricted to a single level meet 5046 5047 Fortran Note: 5048 `coveringPoints` must be declared with 5049 .vb 5050 PetscInt, pointer :: coveringPoints(:) 5051 .ve 5052 5053 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5054 @*/ 5055 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 5056 { 5057 DM_Plex *mesh = (DM_Plex *)dm->data; 5058 PetscInt *meet[2]; 5059 PetscInt meetSize, i = 0; 5060 PetscInt dof, off, p, c, m; 5061 PetscInt maxConeSize; 5062 5063 PetscFunctionBegin; 5064 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5065 PetscAssertPointer(points, 3); 5066 PetscAssertPointer(numCoveringPoints, 4); 5067 PetscAssertPointer(coveringPoints, 5); 5068 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 5069 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 5070 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 5071 /* Copy in cone of first point */ 5072 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 5073 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 5074 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5075 /* Check each successive cone */ 5076 for (p = 1; p < numPoints; ++p) { 5077 PetscInt newMeetSize = 0; 5078 5079 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5080 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5081 for (c = 0; c < dof; ++c) { 5082 const PetscInt point = mesh->cones[off + c]; 5083 5084 for (m = 0; m < meetSize; ++m) { 5085 if (point == meet[i][m]) { 5086 meet[1 - i][newMeetSize++] = point; 5087 break; 5088 } 5089 } 5090 } 5091 meetSize = newMeetSize; 5092 i = 1 - i; 5093 } 5094 *numCoveringPoints = meetSize; 5095 *coveringPoints = meet[i]; 5096 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5097 PetscFunctionReturn(PETSC_SUCCESS); 5098 } 5099 5100 /*@C 5101 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5102 5103 Not Collective 5104 5105 Input Parameters: 5106 + dm - The `DMPLEX` object 5107 . numPoints - The number of input points for the meet 5108 - points - The input points 5109 5110 Output Parameters: 5111 + numCoveredPoints - The number of points in the meet 5112 - coveredPoints - The points in the meet 5113 5114 Level: intermediate 5115 5116 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5117 @*/ 5118 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5119 { 5120 PetscFunctionBegin; 5121 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5122 if (points) PetscAssertPointer(points, 3); 5123 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5124 PetscAssertPointer(coveredPoints, 5); 5125 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5126 if (numCoveredPoints) *numCoveredPoints = 0; 5127 PetscFunctionReturn(PETSC_SUCCESS); 5128 } 5129 5130 /*@C 5131 DMPlexGetFullMeet - Get an array for the meet of the set of points 5132 5133 Not Collective 5134 5135 Input Parameters: 5136 + dm - The `DMPLEX` object 5137 . numPoints - The number of input points for the meet 5138 - points - The input points, of length `numPoints` 5139 5140 Output Parameters: 5141 + numCoveredPoints - The number of points in the meet 5142 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5143 5144 Level: intermediate 5145 5146 Fortran Notes: 5147 `coveredPoints` must be declared with 5148 .vb 5149 PetscInt, pointer :: coveredPoints(:) 5150 .ve 5151 5152 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5153 @*/ 5154 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5155 { 5156 PetscInt *offsets, **closures; 5157 PetscInt *meet[2]; 5158 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5159 PetscInt p, h, c, m, mc; 5160 5161 PetscFunctionBegin; 5162 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5163 PetscAssertPointer(points, 3); 5164 PetscAssertPointer(numCoveredPoints, 4); 5165 PetscAssertPointer(coveredPoints, 5); 5166 5167 PetscCall(DMPlexGetDepth(dm, &height)); 5168 PetscCall(PetscMalloc1(numPoints, &closures)); 5169 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5170 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5171 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5172 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5173 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5174 5175 for (p = 0; p < numPoints; ++p) { 5176 PetscInt closureSize; 5177 5178 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5179 5180 offsets[p * (height + 2) + 0] = 0; 5181 for (h = 0; h < height + 1; ++h) { 5182 PetscInt pStart, pEnd, i; 5183 5184 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5185 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5186 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5187 offsets[p * (height + 2) + h + 1] = i; 5188 break; 5189 } 5190 } 5191 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5192 } 5193 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); 5194 } 5195 for (h = 0; h < height + 1; ++h) { 5196 PetscInt dof; 5197 5198 /* Copy in cone of first point */ 5199 dof = offsets[h + 1] - offsets[h]; 5200 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5201 /* Check each successive cone */ 5202 for (p = 1; p < numPoints && meetSize; ++p) { 5203 PetscInt newMeetSize = 0; 5204 5205 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5206 for (c = 0; c < dof; ++c) { 5207 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5208 5209 for (m = 0; m < meetSize; ++m) { 5210 if (point == meet[i][m]) { 5211 meet[1 - i][newMeetSize++] = point; 5212 break; 5213 } 5214 } 5215 } 5216 meetSize = newMeetSize; 5217 i = 1 - i; 5218 } 5219 if (meetSize) break; 5220 } 5221 *numCoveredPoints = meetSize; 5222 *coveredPoints = meet[i]; 5223 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5224 PetscCall(PetscFree(closures)); 5225 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5226 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5227 PetscFunctionReturn(PETSC_SUCCESS); 5228 } 5229 5230 /*@ 5231 DMPlexEqual - Determine if two `DM` have the same topology 5232 5233 Not Collective 5234 5235 Input Parameters: 5236 + dmA - A `DMPLEX` object 5237 - dmB - A `DMPLEX` object 5238 5239 Output Parameter: 5240 . equal - `PETSC_TRUE` if the topologies are identical 5241 5242 Level: intermediate 5243 5244 Note: 5245 We are not solving graph isomorphism, so we do not permute. 5246 5247 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5248 @*/ 5249 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5250 { 5251 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5252 5253 PetscFunctionBegin; 5254 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5255 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5256 PetscAssertPointer(equal, 3); 5257 5258 *equal = PETSC_FALSE; 5259 PetscCall(DMPlexGetDepth(dmA, &depth)); 5260 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5261 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5262 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5263 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5264 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5265 for (p = pStart; p < pEnd; ++p) { 5266 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5267 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5268 5269 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5270 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5271 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5272 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5273 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5274 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5275 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5276 for (c = 0; c < coneSize; ++c) { 5277 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5278 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5279 } 5280 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5281 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5282 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5283 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5284 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5285 for (s = 0; s < supportSize; ++s) { 5286 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5287 } 5288 } 5289 *equal = PETSC_TRUE; 5290 PetscFunctionReturn(PETSC_SUCCESS); 5291 } 5292 5293 /*@ 5294 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5295 5296 Not Collective 5297 5298 Input Parameters: 5299 + dm - The `DMPLEX` 5300 . cellDim - The cell dimension 5301 - numCorners - The number of vertices on a cell 5302 5303 Output Parameter: 5304 . numFaceVertices - The number of vertices on a face 5305 5306 Level: developer 5307 5308 Note: 5309 Of course this can only work for a restricted set of symmetric shapes 5310 5311 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5312 @*/ 5313 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5314 { 5315 MPI_Comm comm; 5316 5317 PetscFunctionBegin; 5318 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5319 PetscAssertPointer(numFaceVertices, 4); 5320 switch (cellDim) { 5321 case 0: 5322 *numFaceVertices = 0; 5323 break; 5324 case 1: 5325 *numFaceVertices = 1; 5326 break; 5327 case 2: 5328 switch (numCorners) { 5329 case 3: /* triangle */ 5330 *numFaceVertices = 2; /* Edge has 2 vertices */ 5331 break; 5332 case 4: /* quadrilateral */ 5333 *numFaceVertices = 2; /* Edge has 2 vertices */ 5334 break; 5335 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5336 *numFaceVertices = 3; /* Edge has 3 vertices */ 5337 break; 5338 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5339 *numFaceVertices = 3; /* Edge has 3 vertices */ 5340 break; 5341 default: 5342 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5343 } 5344 break; 5345 case 3: 5346 switch (numCorners) { 5347 case 4: /* tetradehdron */ 5348 *numFaceVertices = 3; /* Face has 3 vertices */ 5349 break; 5350 case 6: /* tet cohesive cells */ 5351 *numFaceVertices = 4; /* Face has 4 vertices */ 5352 break; 5353 case 8: /* hexahedron */ 5354 *numFaceVertices = 4; /* Face has 4 vertices */ 5355 break; 5356 case 9: /* tet cohesive Lagrange cells */ 5357 *numFaceVertices = 6; /* Face has 6 vertices */ 5358 break; 5359 case 10: /* quadratic tetrahedron */ 5360 *numFaceVertices = 6; /* Face has 6 vertices */ 5361 break; 5362 case 12: /* hex cohesive Lagrange cells */ 5363 *numFaceVertices = 6; /* Face has 6 vertices */ 5364 break; 5365 case 18: /* quadratic tet cohesive Lagrange cells */ 5366 *numFaceVertices = 6; /* Face has 6 vertices */ 5367 break; 5368 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5369 *numFaceVertices = 9; /* Face has 9 vertices */ 5370 break; 5371 default: 5372 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5373 } 5374 break; 5375 default: 5376 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5377 } 5378 PetscFunctionReturn(PETSC_SUCCESS); 5379 } 5380 5381 /*@ 5382 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5383 5384 Not Collective 5385 5386 Input Parameter: 5387 . dm - The `DMPLEX` object 5388 5389 Output Parameter: 5390 . depthLabel - The `DMLabel` recording point depth 5391 5392 Level: developer 5393 5394 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5395 @*/ 5396 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5397 { 5398 PetscFunctionBegin; 5399 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5400 PetscAssertPointer(depthLabel, 2); 5401 *depthLabel = dm->depthLabel; 5402 PetscFunctionReturn(PETSC_SUCCESS); 5403 } 5404 5405 /*@ 5406 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5407 5408 Not Collective 5409 5410 Input Parameter: 5411 . dm - The `DMPLEX` object 5412 5413 Output Parameter: 5414 . depth - The number of strata (breadth first levels) in the DAG 5415 5416 Level: developer 5417 5418 Notes: 5419 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5420 5421 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5422 5423 An empty mesh gives -1. 5424 5425 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5426 @*/ 5427 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5428 { 5429 DM_Plex *mesh = (DM_Plex *)dm->data; 5430 DMLabel label; 5431 PetscInt d = -1; 5432 5433 PetscFunctionBegin; 5434 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5435 PetscAssertPointer(depth, 2); 5436 if (mesh->tr) { 5437 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5438 } else { 5439 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5440 // Allow missing depths 5441 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5442 *depth = d; 5443 } 5444 PetscFunctionReturn(PETSC_SUCCESS); 5445 } 5446 5447 /*@ 5448 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5449 5450 Not Collective 5451 5452 Input Parameters: 5453 + dm - The `DMPLEX` object 5454 - depth - The requested depth 5455 5456 Output Parameters: 5457 + start - The first point at this `depth` 5458 - end - One beyond the last point at this `depth` 5459 5460 Level: developer 5461 5462 Notes: 5463 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5464 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5465 higher dimension, e.g., "edges". 5466 5467 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5468 @*/ 5469 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PeOp PetscInt *start, PeOp PetscInt *end) 5470 { 5471 DM_Plex *mesh = (DM_Plex *)dm->data; 5472 DMLabel label; 5473 PetscInt pStart, pEnd; 5474 5475 PetscFunctionBegin; 5476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5477 if (start) { 5478 PetscAssertPointer(start, 3); 5479 *start = 0; 5480 } 5481 if (end) { 5482 PetscAssertPointer(end, 4); 5483 *end = 0; 5484 } 5485 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5486 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5487 if (depth < 0) { 5488 if (start) *start = pStart; 5489 if (end) *end = pEnd; 5490 PetscFunctionReturn(PETSC_SUCCESS); 5491 } 5492 if (mesh->tr) { 5493 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5494 } else { 5495 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5496 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5497 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5498 } 5499 PetscFunctionReturn(PETSC_SUCCESS); 5500 } 5501 5502 /*@ 5503 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5504 5505 Not Collective 5506 5507 Input Parameters: 5508 + dm - The `DMPLEX` object 5509 - height - The requested height 5510 5511 Output Parameters: 5512 + start - The first point at this `height` 5513 - end - One beyond the last point at this `height` 5514 5515 Level: developer 5516 5517 Notes: 5518 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5519 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5520 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5521 5522 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5523 @*/ 5524 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PeOp PetscInt *start, PeOp PetscInt *end) 5525 { 5526 DMLabel label; 5527 PetscInt depth, pStart, pEnd; 5528 5529 PetscFunctionBegin; 5530 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5531 if (start) { 5532 PetscAssertPointer(start, 3); 5533 *start = 0; 5534 } 5535 if (end) { 5536 PetscAssertPointer(end, 4); 5537 *end = 0; 5538 } 5539 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5540 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5541 if (height < 0) { 5542 if (start) *start = pStart; 5543 if (end) *end = pEnd; 5544 PetscFunctionReturn(PETSC_SUCCESS); 5545 } 5546 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5547 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5548 else PetscCall(DMGetDimension(dm, &depth)); 5549 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5550 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5551 PetscFunctionReturn(PETSC_SUCCESS); 5552 } 5553 5554 /*@ 5555 DMPlexGetPointDepth - Get the `depth` of a given point 5556 5557 Not Collective 5558 5559 Input Parameters: 5560 + dm - The `DMPLEX` object 5561 - point - The point 5562 5563 Output Parameter: 5564 . depth - The depth of the `point` 5565 5566 Level: intermediate 5567 5568 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5569 @*/ 5570 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5571 { 5572 PetscFunctionBegin; 5573 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5574 PetscAssertPointer(depth, 3); 5575 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5576 PetscFunctionReturn(PETSC_SUCCESS); 5577 } 5578 5579 /*@ 5580 DMPlexGetPointHeight - Get the `height` of a given point 5581 5582 Not Collective 5583 5584 Input Parameters: 5585 + dm - The `DMPLEX` object 5586 - point - The point 5587 5588 Output Parameter: 5589 . height - The height of the `point` 5590 5591 Level: intermediate 5592 5593 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5594 @*/ 5595 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5596 { 5597 PetscInt n, pDepth; 5598 5599 PetscFunctionBegin; 5600 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5601 PetscAssertPointer(height, 3); 5602 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5603 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5604 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5605 PetscFunctionReturn(PETSC_SUCCESS); 5606 } 5607 5608 /*@ 5609 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5610 5611 Not Collective 5612 5613 Input Parameter: 5614 . dm - The `DMPLEX` object 5615 5616 Output Parameter: 5617 . celltypeLabel - The `DMLabel` recording cell polytope type 5618 5619 Level: developer 5620 5621 Note: 5622 This function will trigger automatica computation of cell types. This can be disabled by calling 5623 `DMCreateLabel`(dm, "celltype") beforehand. 5624 5625 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5626 @*/ 5627 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5628 { 5629 PetscFunctionBegin; 5630 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5631 PetscAssertPointer(celltypeLabel, 2); 5632 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5633 *celltypeLabel = dm->celltypeLabel; 5634 PetscFunctionReturn(PETSC_SUCCESS); 5635 } 5636 5637 /*@ 5638 DMPlexGetCellType - Get the polytope type of a given cell 5639 5640 Not Collective 5641 5642 Input Parameters: 5643 + dm - The `DMPLEX` object 5644 - cell - The cell 5645 5646 Output Parameter: 5647 . celltype - The polytope type of the cell 5648 5649 Level: intermediate 5650 5651 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5652 @*/ 5653 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5654 { 5655 DM_Plex *mesh = (DM_Plex *)dm->data; 5656 DMLabel label; 5657 PetscInt ct; 5658 5659 PetscFunctionBegin; 5660 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5661 PetscAssertPointer(celltype, 3); 5662 if (mesh->tr) { 5663 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5664 } else { 5665 PetscInt pStart, pEnd; 5666 5667 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5668 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5669 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5670 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5671 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5672 for (PetscInt p = pStart; p < pEnd; p++) { 5673 PetscCall(DMLabelGetValue(label, p, &ct)); 5674 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5675 } 5676 } 5677 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5678 if (PetscDefined(USE_DEBUG)) { 5679 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5680 PetscCall(DMLabelGetValue(label, cell, &ct)); 5681 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5682 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5683 } 5684 } 5685 PetscFunctionReturn(PETSC_SUCCESS); 5686 } 5687 5688 /*@ 5689 DMPlexSetCellType - Set the polytope type of a given cell 5690 5691 Not Collective 5692 5693 Input Parameters: 5694 + dm - The `DMPLEX` object 5695 . cell - The cell 5696 - celltype - The polytope type of the cell 5697 5698 Level: advanced 5699 5700 Note: 5701 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5702 is executed. This function will override the computed type. However, if automatic classification will not succeed 5703 and a user wants to manually specify all types, the classification must be disabled by calling 5704 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5705 5706 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5707 @*/ 5708 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5709 { 5710 DM_Plex *mesh = (DM_Plex *)dm->data; 5711 DMLabel label; 5712 PetscInt pStart, pEnd; 5713 5714 PetscFunctionBegin; 5715 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5716 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5717 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5718 PetscCall(DMLabelSetValue(label, cell, celltype)); 5719 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5720 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5721 PetscFunctionReturn(PETSC_SUCCESS); 5722 } 5723 5724 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5725 { 5726 PetscSection section; 5727 PetscInt maxHeight; 5728 const char *prefix; 5729 5730 PetscFunctionBegin; 5731 PetscCall(DMClone(dm, cdm)); 5732 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5733 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5734 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5735 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5736 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5737 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5738 PetscCall(DMSetLocalSection(*cdm, section)); 5739 PetscCall(PetscSectionDestroy(§ion)); 5740 5741 PetscCall(DMSetNumFields(*cdm, 1)); 5742 PetscCall(DMCreateDS(*cdm)); 5743 (*cdm)->cloneOpts = PETSC_TRUE; 5744 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5745 PetscFunctionReturn(PETSC_SUCCESS); 5746 } 5747 5748 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5749 { 5750 Vec coordsLocal, cellCoordsLocal; 5751 DM coordsDM, cellCoordsDM; 5752 5753 PetscFunctionBegin; 5754 *field = NULL; 5755 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5756 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5757 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5758 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5759 if (coordsLocal && coordsDM) { 5760 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5761 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5762 } 5763 PetscFunctionReturn(PETSC_SUCCESS); 5764 } 5765 5766 /*@ 5767 DMPlexGetConeSection - Return a section which describes the layout of cone data 5768 5769 Not Collective 5770 5771 Input Parameter: 5772 . dm - The `DMPLEX` object 5773 5774 Output Parameter: 5775 . section - The `PetscSection` object 5776 5777 Level: developer 5778 5779 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5780 @*/ 5781 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5782 { 5783 DM_Plex *mesh = (DM_Plex *)dm->data; 5784 5785 PetscFunctionBegin; 5786 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5787 if (section) *section = mesh->coneSection; 5788 PetscFunctionReturn(PETSC_SUCCESS); 5789 } 5790 5791 /*@ 5792 DMPlexGetSupportSection - Return a section which describes the layout of support data 5793 5794 Not Collective 5795 5796 Input Parameter: 5797 . dm - The `DMPLEX` object 5798 5799 Output Parameter: 5800 . section - The `PetscSection` object 5801 5802 Level: developer 5803 5804 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5805 @*/ 5806 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5807 { 5808 DM_Plex *mesh = (DM_Plex *)dm->data; 5809 5810 PetscFunctionBegin; 5811 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5812 if (section) *section = mesh->supportSection; 5813 PetscFunctionReturn(PETSC_SUCCESS); 5814 } 5815 5816 /*@C 5817 DMPlexGetCones - Return cone data 5818 5819 Not Collective 5820 5821 Input Parameter: 5822 . dm - The `DMPLEX` object 5823 5824 Output Parameter: 5825 . cones - The cone for each point 5826 5827 Level: developer 5828 5829 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5830 @*/ 5831 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5832 { 5833 DM_Plex *mesh = (DM_Plex *)dm->data; 5834 5835 PetscFunctionBegin; 5836 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5837 if (cones) *cones = mesh->cones; 5838 PetscFunctionReturn(PETSC_SUCCESS); 5839 } 5840 5841 /*@C 5842 DMPlexGetConeOrientations - Return cone orientation data 5843 5844 Not Collective 5845 5846 Input Parameter: 5847 . dm - The `DMPLEX` object 5848 5849 Output Parameter: 5850 . coneOrientations - The array of cone orientations for all points 5851 5852 Level: developer 5853 5854 Notes: 5855 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5856 as returned by `DMPlexGetConeOrientation()`. 5857 5858 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5859 5860 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5861 @*/ 5862 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5863 { 5864 DM_Plex *mesh = (DM_Plex *)dm->data; 5865 5866 PetscFunctionBegin; 5867 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5868 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5869 PetscFunctionReturn(PETSC_SUCCESS); 5870 } 5871 5872 /* FEM Support */ 5873 5874 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5875 { 5876 PetscInt depth; 5877 5878 PetscFunctionBegin; 5879 PetscCall(DMPlexGetDepth(plex, &depth)); 5880 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5881 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5882 PetscFunctionReturn(PETSC_SUCCESS); 5883 } 5884 5885 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5886 { 5887 PetscInt depth; 5888 5889 PetscFunctionBegin; 5890 PetscCall(DMPlexGetDepth(plex, &depth)); 5891 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5892 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5893 PetscFunctionReturn(PETSC_SUCCESS); 5894 } 5895 5896 /* 5897 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5898 representing a line in the section. 5899 */ 5900 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5901 { 5902 PetscObject obj; 5903 PetscClassId id; 5904 PetscFE fe = NULL; 5905 5906 PetscFunctionBeginHot; 5907 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5908 PetscCall(DMGetField(dm, field, NULL, &obj)); 5909 PetscCall(PetscObjectGetClassId(obj, &id)); 5910 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5911 5912 if (!fe) { 5913 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5914 /* An order k SEM disc has k-1 dofs on an edge */ 5915 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5916 *k = *k / *Nc + 1; 5917 } else { 5918 PetscInt dual_space_size, dim; 5919 PetscDualSpace dsp; 5920 5921 PetscCall(DMGetDimension(dm, &dim)); 5922 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5923 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5924 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5925 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5926 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5927 } 5928 PetscFunctionReturn(PETSC_SUCCESS); 5929 } 5930 5931 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5932 { 5933 PetscFunctionBeginHot; 5934 if (tensor) { 5935 *dof = PetscPowInt(k + 1, dim); 5936 } else { 5937 switch (dim) { 5938 case 1: 5939 *dof = k + 1; 5940 break; 5941 case 2: 5942 *dof = ((k + 1) * (k + 2)) / 2; 5943 break; 5944 case 3: 5945 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5946 break; 5947 default: 5948 *dof = 0; 5949 } 5950 } 5951 PetscFunctionReturn(PETSC_SUCCESS); 5952 } 5953 5954 /*@ 5955 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5956 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5957 section provided (or the section of the `DM`). 5958 5959 Input Parameters: 5960 + dm - The `DM` 5961 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5962 - section - The `PetscSection` to reorder, or `NULL` for the default section 5963 5964 Example: 5965 A typical interpolated single-quad mesh might order points as 5966 .vb 5967 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5968 5969 v4 -- e6 -- v3 5970 | | 5971 e7 c0 e8 5972 | | 5973 v1 -- e5 -- v2 5974 .ve 5975 5976 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5977 dofs in the order of points, e.g., 5978 .vb 5979 c0 -> [0,1,2,3] 5980 v1 -> [4] 5981 ... 5982 e5 -> [8, 9] 5983 .ve 5984 5985 which corresponds to the dofs 5986 .vb 5987 6 10 11 7 5988 13 2 3 15 5989 12 0 1 14 5990 4 8 9 5 5991 .ve 5992 5993 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5994 .vb 5995 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5996 .ve 5997 5998 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5999 .vb 6000 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 6001 .ve 6002 6003 Level: developer 6004 6005 Notes: 6006 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 6007 degree of the basis. 6008 6009 This is required to run with libCEED. 6010 6011 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 6012 @*/ 6013 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 6014 { 6015 DMLabel label; 6016 PetscInt dim, depth = -1, eStart = -1, Nf; 6017 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 6018 6019 PetscFunctionBegin; 6020 PetscCall(DMGetDimension(dm, &dim)); 6021 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 6022 if (point < 0) { 6023 PetscInt sStart, sEnd; 6024 6025 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6026 point = sEnd - sStart ? sStart : point; 6027 } 6028 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6029 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6030 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6031 if (depth == 1) { 6032 eStart = point; 6033 } else if (depth == dim) { 6034 const PetscInt *cone; 6035 6036 PetscCall(DMPlexGetCone(dm, point, &cone)); 6037 if (dim == 2) eStart = cone[0]; 6038 else if (dim == 3) { 6039 const PetscInt *cone2; 6040 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6041 eStart = cone2[0]; 6042 } 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); 6043 } 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); 6044 6045 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6046 for (PetscInt d = 1; d <= dim; d++) { 6047 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6048 PetscInt *perm; 6049 6050 for (f = 0; f < Nf; ++f) { 6051 PetscInt dof; 6052 6053 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6054 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6055 if (!continuous && d < dim) continue; 6056 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6057 size += dof * Nc; 6058 } 6059 PetscCall(PetscMalloc1(size, &perm)); 6060 for (f = 0; f < Nf; ++f) { 6061 switch (d) { 6062 case 1: 6063 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6064 if (!continuous && d < dim) continue; 6065 /* 6066 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6067 We want [ vtx0; edge of length k-1; vtx1 ] 6068 */ 6069 if (continuous) { 6070 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6071 for (i = 0; i < k - 1; i++) 6072 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6073 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6074 foffset = offset; 6075 } else { 6076 PetscInt dof; 6077 6078 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6079 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6080 foffset = offset; 6081 } 6082 break; 6083 case 2: 6084 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6085 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6086 if (!continuous && d < dim) continue; 6087 /* The SEM order is 6088 6089 v_lb, {e_b}, v_rb, 6090 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6091 v_lt, reverse {e_t}, v_rt 6092 */ 6093 if (continuous) { 6094 const PetscInt of = 0; 6095 const PetscInt oeb = of + PetscSqr(k - 1); 6096 const PetscInt oer = oeb + (k - 1); 6097 const PetscInt oet = oer + (k - 1); 6098 const PetscInt oel = oet + (k - 1); 6099 const PetscInt ovlb = oel + (k - 1); 6100 const PetscInt ovrb = ovlb + 1; 6101 const PetscInt ovrt = ovrb + 1; 6102 const PetscInt ovlt = ovrt + 1; 6103 PetscInt o; 6104 6105 /* bottom */ 6106 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6107 for (o = oeb; o < oer; ++o) 6108 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6109 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6110 /* middle */ 6111 for (i = 0; i < k - 1; ++i) { 6112 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6113 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6114 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6115 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6116 } 6117 /* top */ 6118 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6119 for (o = oel - 1; o >= oet; --o) 6120 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6121 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6122 foffset = offset; 6123 } else { 6124 PetscInt dof; 6125 6126 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6127 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6128 foffset = offset; 6129 } 6130 break; 6131 case 3: 6132 /* The original hex closure is 6133 6134 {c, 6135 f_b, f_t, f_f, f_b, f_r, f_l, 6136 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6137 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6138 */ 6139 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6140 if (!continuous && d < dim) continue; 6141 /* The SEM order is 6142 Bottom Slice 6143 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6144 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6145 v_blb, {e_bb}, v_brb, 6146 6147 Middle Slice (j) 6148 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6149 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6150 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6151 6152 Top Slice 6153 v_tlf, {e_tf}, v_trf, 6154 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6155 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6156 */ 6157 if (continuous) { 6158 const PetscInt oc = 0; 6159 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6160 const PetscInt oft = ofb + PetscSqr(k - 1); 6161 const PetscInt off = oft + PetscSqr(k - 1); 6162 const PetscInt ofk = off + PetscSqr(k - 1); 6163 const PetscInt ofr = ofk + PetscSqr(k - 1); 6164 const PetscInt ofl = ofr + PetscSqr(k - 1); 6165 const PetscInt oebl = ofl + PetscSqr(k - 1); 6166 const PetscInt oebb = oebl + (k - 1); 6167 const PetscInt oebr = oebb + (k - 1); 6168 const PetscInt oebf = oebr + (k - 1); 6169 const PetscInt oetf = oebf + (k - 1); 6170 const PetscInt oetr = oetf + (k - 1); 6171 const PetscInt oetb = oetr + (k - 1); 6172 const PetscInt oetl = oetb + (k - 1); 6173 const PetscInt oerf = oetl + (k - 1); 6174 const PetscInt oelf = oerf + (k - 1); 6175 const PetscInt oelb = oelf + (k - 1); 6176 const PetscInt oerb = oelb + (k - 1); 6177 const PetscInt ovblf = oerb + (k - 1); 6178 const PetscInt ovblb = ovblf + 1; 6179 const PetscInt ovbrb = ovblb + 1; 6180 const PetscInt ovbrf = ovbrb + 1; 6181 const PetscInt ovtlf = ovbrf + 1; 6182 const PetscInt ovtrf = ovtlf + 1; 6183 const PetscInt ovtrb = ovtrf + 1; 6184 const PetscInt ovtlb = ovtrb + 1; 6185 PetscInt o, n; 6186 6187 /* Bottom Slice */ 6188 /* bottom */ 6189 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6190 for (o = oetf - 1; o >= oebf; --o) 6191 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6192 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6193 /* middle */ 6194 for (i = 0; i < k - 1; ++i) { 6195 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6196 for (n = 0; n < k - 1; ++n) { 6197 o = ofb + n * (k - 1) + i; 6198 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6199 } 6200 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6201 } 6202 /* top */ 6203 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6204 for (o = oebb; o < oebr; ++o) 6205 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6206 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6207 6208 /* Middle Slice */ 6209 for (j = 0; j < k - 1; ++j) { 6210 /* bottom */ 6211 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6212 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6213 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6214 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6215 /* middle */ 6216 for (i = 0; i < k - 1; ++i) { 6217 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6218 for (n = 0; n < k - 1; ++n) 6219 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6220 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6221 } 6222 /* top */ 6223 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6224 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6225 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6226 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6227 } 6228 6229 /* Top Slice */ 6230 /* bottom */ 6231 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6232 for (o = oetf; o < oetr; ++o) 6233 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6234 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6235 /* middle */ 6236 for (i = 0; i < k - 1; ++i) { 6237 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6238 for (n = 0; n < k - 1; ++n) 6239 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6240 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6241 } 6242 /* top */ 6243 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6244 for (o = oetl - 1; o >= oetb; --o) 6245 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6246 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6247 6248 foffset = offset; 6249 } else { 6250 PetscInt dof; 6251 6252 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6253 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6254 foffset = offset; 6255 } 6256 break; 6257 default: 6258 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6259 } 6260 } 6261 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6262 /* Check permutation */ 6263 { 6264 PetscInt *check; 6265 6266 PetscCall(PetscMalloc1(size, &check)); 6267 for (i = 0; i < size; ++i) { 6268 check[i] = -1; 6269 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6270 } 6271 for (i = 0; i < size; ++i) check[perm[i]] = i; 6272 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6273 PetscCall(PetscFree(check)); 6274 } 6275 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6276 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6277 PetscInt *loc_perm; 6278 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6279 for (PetscInt i = 0; i < size; i++) { 6280 loc_perm[i] = perm[i]; 6281 loc_perm[size + i] = size + perm[i]; 6282 } 6283 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6284 } 6285 } 6286 PetscFunctionReturn(PETSC_SUCCESS); 6287 } 6288 6289 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6290 { 6291 PetscDS prob; 6292 PetscInt depth, Nf, h; 6293 DMLabel label; 6294 6295 PetscFunctionBeginHot; 6296 PetscCall(DMGetDS(dm, &prob)); 6297 Nf = prob->Nf; 6298 label = dm->depthLabel; 6299 *dspace = NULL; 6300 if (field < Nf) { 6301 PetscObject disc = prob->disc[field]; 6302 6303 if (disc->classid == PETSCFE_CLASSID) { 6304 PetscDualSpace dsp; 6305 6306 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6307 PetscCall(DMLabelGetNumValues(label, &depth)); 6308 PetscCall(DMLabelGetValue(label, point, &h)); 6309 h = depth - 1 - h; 6310 if (h) { 6311 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6312 } else { 6313 *dspace = dsp; 6314 } 6315 } 6316 } 6317 PetscFunctionReturn(PETSC_SUCCESS); 6318 } 6319 6320 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6321 { 6322 PetscScalar *array; 6323 const PetscScalar *vArray; 6324 const PetscInt *cone, *coneO; 6325 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6326 6327 PetscFunctionBeginHot; 6328 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6329 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6330 PetscCall(DMPlexGetCone(dm, point, &cone)); 6331 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6332 if (!values || !*values) { 6333 if ((point >= pStart) && (point < pEnd)) { 6334 PetscInt dof; 6335 6336 PetscCall(PetscSectionGetDof(section, point, &dof)); 6337 size += dof; 6338 } 6339 for (p = 0; p < numPoints; ++p) { 6340 const PetscInt cp = cone[p]; 6341 PetscInt dof; 6342 6343 if ((cp < pStart) || (cp >= pEnd)) continue; 6344 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6345 size += dof; 6346 } 6347 if (!values) { 6348 if (csize) *csize = size; 6349 PetscFunctionReturn(PETSC_SUCCESS); 6350 } 6351 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6352 } else { 6353 array = *values; 6354 } 6355 size = 0; 6356 PetscCall(VecGetArrayRead(v, &vArray)); 6357 if ((point >= pStart) && (point < pEnd)) { 6358 PetscInt dof, off, d; 6359 const PetscScalar *varr; 6360 6361 PetscCall(PetscSectionGetDof(section, point, &dof)); 6362 PetscCall(PetscSectionGetOffset(section, point, &off)); 6363 varr = PetscSafePointerPlusOffset(vArray, off); 6364 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6365 size += dof; 6366 } 6367 for (p = 0; p < numPoints; ++p) { 6368 const PetscInt cp = cone[p]; 6369 PetscInt o = coneO[p]; 6370 PetscInt dof, off, d; 6371 const PetscScalar *varr; 6372 6373 if ((cp < pStart) || (cp >= pEnd)) continue; 6374 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6375 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6376 varr = PetscSafePointerPlusOffset(vArray, off); 6377 if (o >= 0) { 6378 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6379 } else { 6380 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6381 } 6382 size += dof; 6383 } 6384 PetscCall(VecRestoreArrayRead(v, &vArray)); 6385 if (!*values) { 6386 if (csize) *csize = size; 6387 *values = array; 6388 } else { 6389 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6390 *csize = size; 6391 } 6392 PetscFunctionReturn(PETSC_SUCCESS); 6393 } 6394 6395 /* Compress out points not in the section */ 6396 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6397 { 6398 const PetscInt np = *numPoints; 6399 PetscInt pStart, pEnd, p, q; 6400 6401 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6402 for (p = 0, q = 0; p < np; ++p) { 6403 const PetscInt r = points[p * 2]; 6404 if ((r >= pStart) && (r < pEnd)) { 6405 points[q * 2] = r; 6406 points[q * 2 + 1] = points[p * 2 + 1]; 6407 ++q; 6408 } 6409 } 6410 *numPoints = q; 6411 return PETSC_SUCCESS; 6412 } 6413 6414 /* Compressed closure does not apply closure permutation */ 6415 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6416 { 6417 const PetscInt *cla = NULL; 6418 PetscInt np, *pts = NULL; 6419 6420 PetscFunctionBeginHot; 6421 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6422 if (!ornt && *clPoints) { 6423 PetscInt dof, off; 6424 6425 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6426 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6427 PetscCall(ISGetIndices(*clPoints, &cla)); 6428 np = dof / 2; 6429 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6430 } else { 6431 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6432 PetscCall(CompressPoints_Private(section, &np, pts)); 6433 } 6434 *numPoints = np; 6435 *points = pts; 6436 *clp = cla; 6437 PetscFunctionReturn(PETSC_SUCCESS); 6438 } 6439 6440 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6441 { 6442 PetscFunctionBeginHot; 6443 if (!*clPoints) { 6444 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6445 } else { 6446 PetscCall(ISRestoreIndices(*clPoints, clp)); 6447 } 6448 *numPoints = 0; 6449 *points = NULL; 6450 *clSec = NULL; 6451 *clPoints = NULL; 6452 *clp = NULL; 6453 PetscFunctionReturn(PETSC_SUCCESS); 6454 } 6455 6456 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6457 { 6458 PetscInt offset = 0, p; 6459 const PetscInt **perms = NULL; 6460 const PetscScalar **flips = NULL; 6461 6462 PetscFunctionBeginHot; 6463 *size = 0; 6464 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6465 for (p = 0; p < numPoints; p++) { 6466 const PetscInt point = points[2 * p]; 6467 const PetscInt *perm = perms ? perms[p] : NULL; 6468 const PetscScalar *flip = flips ? flips[p] : NULL; 6469 PetscInt dof, off, d; 6470 const PetscScalar *varr; 6471 6472 PetscCall(PetscSectionGetDof(section, point, &dof)); 6473 PetscCall(PetscSectionGetOffset(section, point, &off)); 6474 varr = PetscSafePointerPlusOffset(vArray, off); 6475 if (clperm) { 6476 if (perm) { 6477 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6478 } else { 6479 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6480 } 6481 if (flip) { 6482 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6483 } 6484 } else { 6485 if (perm) { 6486 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6487 } else { 6488 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6489 } 6490 if (flip) { 6491 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6492 } 6493 } 6494 offset += dof; 6495 } 6496 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6497 *size = offset; 6498 PetscFunctionReturn(PETSC_SUCCESS); 6499 } 6500 6501 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[]) 6502 { 6503 PetscInt offset = 0, f; 6504 6505 PetscFunctionBeginHot; 6506 *size = 0; 6507 for (f = 0; f < numFields; ++f) { 6508 PetscInt p; 6509 const PetscInt **perms = NULL; 6510 const PetscScalar **flips = NULL; 6511 6512 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6513 for (p = 0; p < numPoints; p++) { 6514 const PetscInt point = points[2 * p]; 6515 PetscInt fdof, foff, b; 6516 const PetscScalar *varr; 6517 const PetscInt *perm = perms ? perms[p] : NULL; 6518 const PetscScalar *flip = flips ? flips[p] : NULL; 6519 6520 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6521 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6522 varr = &vArray[foff]; 6523 if (clperm) { 6524 if (perm) { 6525 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6526 } else { 6527 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6528 } 6529 if (flip) { 6530 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6531 } 6532 } else { 6533 if (perm) { 6534 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6535 } else { 6536 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6537 } 6538 if (flip) { 6539 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6540 } 6541 } 6542 offset += fdof; 6543 } 6544 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6545 } 6546 *size = offset; 6547 PetscFunctionReturn(PETSC_SUCCESS); 6548 } 6549 6550 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6551 { 6552 PetscSection clSection; 6553 IS clPoints; 6554 PetscInt *points = NULL; 6555 const PetscInt *clp, *perm = NULL; 6556 PetscInt depth, numFields, numPoints, asize; 6557 6558 PetscFunctionBeginHot; 6559 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6560 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6561 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6562 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6563 PetscCall(DMPlexGetDepth(dm, &depth)); 6564 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6565 if (depth == 1 && numFields < 2) { 6566 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6567 PetscFunctionReturn(PETSC_SUCCESS); 6568 } 6569 /* Get points */ 6570 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6571 /* Get sizes */ 6572 asize = 0; 6573 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6574 PetscInt dof; 6575 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6576 asize += dof; 6577 } 6578 if (values) { 6579 const PetscScalar *vArray; 6580 PetscInt size; 6581 6582 if (*values) { 6583 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); 6584 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6585 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6586 PetscCall(VecGetArrayRead(v, &vArray)); 6587 /* Get values */ 6588 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6589 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6590 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6591 /* Cleanup array */ 6592 PetscCall(VecRestoreArrayRead(v, &vArray)); 6593 } 6594 if (csize) *csize = asize; 6595 /* Cleanup points */ 6596 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6597 PetscFunctionReturn(PETSC_SUCCESS); 6598 } 6599 6600 /*@C 6601 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6602 6603 Not collective 6604 6605 Input Parameters: 6606 + dm - The `DM` 6607 . section - The section describing the layout in `v`, or `NULL` to use the default section 6608 . v - The local vector 6609 - point - The point in the `DM` 6610 6611 Input/Output Parameters: 6612 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6613 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6614 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6615 6616 Level: intermediate 6617 6618 Notes: 6619 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6620 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6621 assembly function, and a user may already have allocated storage for this operation. 6622 6623 A typical use could be 6624 .vb 6625 values = NULL; 6626 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6627 for (cl = 0; cl < clSize; ++cl) { 6628 <Compute on closure> 6629 } 6630 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6631 .ve 6632 or 6633 .vb 6634 PetscMalloc1(clMaxSize, &values); 6635 for (p = pStart; p < pEnd; ++p) { 6636 clSize = clMaxSize; 6637 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6638 for (cl = 0; cl < clSize; ++cl) { 6639 <Compute on closure> 6640 } 6641 } 6642 PetscFree(values); 6643 .ve 6644 6645 Fortran Notes: 6646 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6647 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6648 6649 `values` must be declared with 6650 .vb 6651 PetscScalar,dimension(:),pointer :: values 6652 .ve 6653 and it will be allocated internally by PETSc to hold the values returned 6654 6655 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6656 @*/ 6657 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6658 { 6659 PetscFunctionBeginHot; 6660 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6661 PetscFunctionReturn(PETSC_SUCCESS); 6662 } 6663 6664 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6665 { 6666 DMLabel depthLabel; 6667 PetscSection clSection; 6668 IS clPoints; 6669 PetscScalar *array; 6670 const PetscScalar *vArray; 6671 PetscInt *points = NULL; 6672 const PetscInt *clp, *perm = NULL; 6673 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6674 6675 PetscFunctionBeginHot; 6676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6677 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6678 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6679 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6680 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6681 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6682 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6683 if (mdepth == 1 && numFields < 2) { 6684 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6685 PetscFunctionReturn(PETSC_SUCCESS); 6686 } 6687 /* Get points */ 6688 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6689 for (clsize = 0, p = 0; p < Np; p++) { 6690 PetscInt dof; 6691 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6692 clsize += dof; 6693 } 6694 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6695 /* Filter points */ 6696 for (p = 0; p < numPoints * 2; p += 2) { 6697 PetscInt dep; 6698 6699 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6700 if (dep != depth) continue; 6701 points[Np * 2 + 0] = points[p]; 6702 points[Np * 2 + 1] = points[p + 1]; 6703 ++Np; 6704 } 6705 /* Get array */ 6706 if (!values || !*values) { 6707 PetscInt asize = 0, dof; 6708 6709 for (p = 0; p < Np * 2; p += 2) { 6710 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6711 asize += dof; 6712 } 6713 if (!values) { 6714 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6715 if (csize) *csize = asize; 6716 PetscFunctionReturn(PETSC_SUCCESS); 6717 } 6718 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6719 } else { 6720 array = *values; 6721 } 6722 PetscCall(VecGetArrayRead(v, &vArray)); 6723 /* Get values */ 6724 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6725 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6726 /* Cleanup points */ 6727 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6728 /* Cleanup array */ 6729 PetscCall(VecRestoreArrayRead(v, &vArray)); 6730 if (!*values) { 6731 if (csize) *csize = size; 6732 *values = array; 6733 } else { 6734 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6735 *csize = size; 6736 } 6737 PetscFunctionReturn(PETSC_SUCCESS); 6738 } 6739 6740 /*@C 6741 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6742 6743 Not collective 6744 6745 Input Parameters: 6746 + dm - The `DM` 6747 . section - The section describing the layout in `v`, or `NULL` to use the default section 6748 . v - The local vector 6749 . point - The point in the `DM` 6750 . csize - The number of values in the closure, or `NULL` 6751 - values - The array of values 6752 6753 Level: intermediate 6754 6755 Note: 6756 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6757 6758 Fortran Note: 6759 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6760 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6761 6762 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6763 @*/ 6764 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6765 { 6766 PetscInt size = 0; 6767 6768 PetscFunctionBegin; 6769 /* Should work without recalculating size */ 6770 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6771 *values = NULL; 6772 PetscFunctionReturn(PETSC_SUCCESS); 6773 } 6774 6775 static inline void add(PetscScalar *x, PetscScalar y) 6776 { 6777 *x += y; 6778 } 6779 static inline void insert(PetscScalar *x, PetscScalar y) 6780 { 6781 *x = y; 6782 } 6783 6784 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[]) 6785 { 6786 PetscInt cdof; /* The number of constraints on this point */ 6787 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6788 PetscScalar *a; 6789 PetscInt off, cind = 0, k; 6790 6791 PetscFunctionBegin; 6792 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6793 PetscCall(PetscSectionGetOffset(section, point, &off)); 6794 a = &array[off]; 6795 if (!cdof || setBC) { 6796 if (clperm) { 6797 if (perm) { 6798 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6799 } else { 6800 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6801 } 6802 } else { 6803 if (perm) { 6804 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6805 } else { 6806 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6807 } 6808 } 6809 } else { 6810 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6811 if (clperm) { 6812 if (perm) { 6813 for (k = 0; k < dof; ++k) { 6814 if ((cind < cdof) && (k == cdofs[cind])) { 6815 ++cind; 6816 continue; 6817 } 6818 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6819 } 6820 } else { 6821 for (k = 0; k < dof; ++k) { 6822 if ((cind < cdof) && (k == cdofs[cind])) { 6823 ++cind; 6824 continue; 6825 } 6826 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6827 } 6828 } 6829 } else { 6830 if (perm) { 6831 for (k = 0; k < dof; ++k) { 6832 if ((cind < cdof) && (k == cdofs[cind])) { 6833 ++cind; 6834 continue; 6835 } 6836 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6837 } 6838 } else { 6839 for (k = 0; k < dof; ++k) { 6840 if ((cind < cdof) && (k == cdofs[cind])) { 6841 ++cind; 6842 continue; 6843 } 6844 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6845 } 6846 } 6847 } 6848 } 6849 PetscFunctionReturn(PETSC_SUCCESS); 6850 } 6851 6852 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[]) 6853 { 6854 PetscInt cdof; /* The number of constraints on this point */ 6855 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6856 PetscScalar *a; 6857 PetscInt off, cind = 0, k; 6858 6859 PetscFunctionBegin; 6860 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6861 PetscCall(PetscSectionGetOffset(section, point, &off)); 6862 a = &array[off]; 6863 if (cdof) { 6864 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6865 if (clperm) { 6866 if (perm) { 6867 for (k = 0; k < dof; ++k) { 6868 if ((cind < cdof) && (k == cdofs[cind])) { 6869 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6870 cind++; 6871 } 6872 } 6873 } else { 6874 for (k = 0; k < dof; ++k) { 6875 if ((cind < cdof) && (k == cdofs[cind])) { 6876 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6877 cind++; 6878 } 6879 } 6880 } 6881 } else { 6882 if (perm) { 6883 for (k = 0; k < dof; ++k) { 6884 if ((cind < cdof) && (k == cdofs[cind])) { 6885 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6886 cind++; 6887 } 6888 } 6889 } else { 6890 for (k = 0; k < dof; ++k) { 6891 if ((cind < cdof) && (k == cdofs[cind])) { 6892 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6893 cind++; 6894 } 6895 } 6896 } 6897 } 6898 } 6899 PetscFunctionReturn(PETSC_SUCCESS); 6900 } 6901 6902 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[]) 6903 { 6904 PetscScalar *a; 6905 PetscInt fdof, foff, fcdof, foffset = *offset; 6906 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6907 PetscInt cind = 0, b; 6908 6909 PetscFunctionBegin; 6910 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6911 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6912 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6913 a = &array[foff]; 6914 if (!fcdof || setBC) { 6915 if (clperm) { 6916 if (perm) { 6917 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6918 } else { 6919 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6920 } 6921 } else { 6922 if (perm) { 6923 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6924 } else { 6925 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6926 } 6927 } 6928 } else { 6929 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6930 if (clperm) { 6931 if (perm) { 6932 for (b = 0; b < fdof; b++) { 6933 if ((cind < fcdof) && (b == fcdofs[cind])) { 6934 ++cind; 6935 continue; 6936 } 6937 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6938 } 6939 } else { 6940 for (b = 0; b < fdof; b++) { 6941 if ((cind < fcdof) && (b == fcdofs[cind])) { 6942 ++cind; 6943 continue; 6944 } 6945 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6946 } 6947 } 6948 } else { 6949 if (perm) { 6950 for (b = 0; b < fdof; b++) { 6951 if ((cind < fcdof) && (b == fcdofs[cind])) { 6952 ++cind; 6953 continue; 6954 } 6955 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6956 } 6957 } else { 6958 for (b = 0; b < fdof; b++) { 6959 if ((cind < fcdof) && (b == fcdofs[cind])) { 6960 ++cind; 6961 continue; 6962 } 6963 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6964 } 6965 } 6966 } 6967 } 6968 *offset += fdof; 6969 PetscFunctionReturn(PETSC_SUCCESS); 6970 } 6971 6972 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[]) 6973 { 6974 PetscScalar *a; 6975 PetscInt fdof, foff, fcdof, foffset = *offset; 6976 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6977 PetscInt Nc, cind = 0, ncind = 0, b; 6978 PetscBool ncSet, fcSet; 6979 6980 PetscFunctionBegin; 6981 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6982 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6983 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6984 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6985 a = &array[foff]; 6986 if (fcdof) { 6987 /* We just override fcdof and fcdofs with Ncc and comps */ 6988 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6989 if (clperm) { 6990 if (perm) { 6991 if (comps) { 6992 for (b = 0; b < fdof; b++) { 6993 ncSet = fcSet = PETSC_FALSE; 6994 if (b % Nc == comps[ncind]) { 6995 ncind = (ncind + 1) % Ncc; 6996 ncSet = PETSC_TRUE; 6997 } 6998 if ((cind < fcdof) && (b == fcdofs[cind])) { 6999 ++cind; 7000 fcSet = PETSC_TRUE; 7001 } 7002 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7003 } 7004 } else { 7005 for (b = 0; b < fdof; b++) { 7006 if ((cind < fcdof) && (b == fcdofs[cind])) { 7007 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7008 ++cind; 7009 } 7010 } 7011 } 7012 } else { 7013 if (comps) { 7014 for (b = 0; b < fdof; b++) { 7015 ncSet = fcSet = PETSC_FALSE; 7016 if (b % Nc == comps[ncind]) { 7017 ncind = (ncind + 1) % Ncc; 7018 ncSet = PETSC_TRUE; 7019 } 7020 if ((cind < fcdof) && (b == fcdofs[cind])) { 7021 ++cind; 7022 fcSet = PETSC_TRUE; 7023 } 7024 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7025 } 7026 } else { 7027 for (b = 0; b < fdof; b++) { 7028 if ((cind < fcdof) && (b == fcdofs[cind])) { 7029 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7030 ++cind; 7031 } 7032 } 7033 } 7034 } 7035 } else { 7036 if (perm) { 7037 if (comps) { 7038 for (b = 0; b < fdof; b++) { 7039 ncSet = fcSet = PETSC_FALSE; 7040 if (b % Nc == comps[ncind]) { 7041 ncind = (ncind + 1) % Ncc; 7042 ncSet = PETSC_TRUE; 7043 } 7044 if ((cind < fcdof) && (b == fcdofs[cind])) { 7045 ++cind; 7046 fcSet = PETSC_TRUE; 7047 } 7048 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7049 } 7050 } else { 7051 for (b = 0; b < fdof; b++) { 7052 if ((cind < fcdof) && (b == fcdofs[cind])) { 7053 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7054 ++cind; 7055 } 7056 } 7057 } 7058 } else { 7059 if (comps) { 7060 for (b = 0; b < fdof; b++) { 7061 ncSet = fcSet = PETSC_FALSE; 7062 if (b % Nc == comps[ncind]) { 7063 ncind = (ncind + 1) % Ncc; 7064 ncSet = PETSC_TRUE; 7065 } 7066 if ((cind < fcdof) && (b == fcdofs[cind])) { 7067 ++cind; 7068 fcSet = PETSC_TRUE; 7069 } 7070 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7071 } 7072 } else { 7073 for (b = 0; b < fdof; b++) { 7074 if ((cind < fcdof) && (b == fcdofs[cind])) { 7075 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7076 ++cind; 7077 } 7078 } 7079 } 7080 } 7081 } 7082 } 7083 *offset += fdof; 7084 PetscFunctionReturn(PETSC_SUCCESS); 7085 } 7086 7087 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7088 { 7089 PetscScalar *array; 7090 const PetscInt *cone, *coneO; 7091 PetscInt pStart, pEnd, p, numPoints, off, dof; 7092 7093 PetscFunctionBeginHot; 7094 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7095 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7096 PetscCall(DMPlexGetCone(dm, point, &cone)); 7097 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7098 PetscCall(VecGetArray(v, &array)); 7099 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7100 const PetscInt cp = !p ? point : cone[p - 1]; 7101 const PetscInt o = !p ? 0 : coneO[p - 1]; 7102 7103 if ((cp < pStart) || (cp >= pEnd)) { 7104 dof = 0; 7105 continue; 7106 } 7107 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7108 /* ADD_VALUES */ 7109 { 7110 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7111 PetscScalar *a; 7112 PetscInt cdof, coff, cind = 0, k; 7113 7114 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7115 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7116 a = &array[coff]; 7117 if (!cdof) { 7118 if (o >= 0) { 7119 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7120 } else { 7121 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7122 } 7123 } else { 7124 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7125 if (o >= 0) { 7126 for (k = 0; k < dof; ++k) { 7127 if ((cind < cdof) && (k == cdofs[cind])) { 7128 ++cind; 7129 continue; 7130 } 7131 a[k] += values[off + k]; 7132 } 7133 } else { 7134 for (k = 0; k < dof; ++k) { 7135 if ((cind < cdof) && (k == cdofs[cind])) { 7136 ++cind; 7137 continue; 7138 } 7139 a[k] += values[off + dof - k - 1]; 7140 } 7141 } 7142 } 7143 } 7144 } 7145 PetscCall(VecRestoreArray(v, &array)); 7146 PetscFunctionReturn(PETSC_SUCCESS); 7147 } 7148 7149 /*@C 7150 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7151 7152 Not collective 7153 7154 Input Parameters: 7155 + dm - The `DM` 7156 . section - The section describing the layout in `v`, or `NULL` to use the default section 7157 . v - The local vector 7158 . point - The point in the `DM` 7159 . values - The array of values 7160 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7161 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7162 7163 Level: intermediate 7164 7165 Note: 7166 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7167 7168 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7169 @*/ 7170 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7171 { 7172 PetscSection clSection; 7173 IS clPoints; 7174 PetscScalar *array; 7175 PetscInt *points = NULL; 7176 const PetscInt *clp, *clperm = NULL; 7177 PetscInt depth, numFields, numPoints, p, clsize; 7178 7179 PetscFunctionBeginHot; 7180 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7181 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7182 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7183 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7184 PetscCall(DMPlexGetDepth(dm, &depth)); 7185 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7186 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7187 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7188 PetscFunctionReturn(PETSC_SUCCESS); 7189 } 7190 /* Get points */ 7191 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7192 for (clsize = 0, p = 0; p < numPoints; p++) { 7193 PetscInt dof; 7194 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7195 clsize += dof; 7196 } 7197 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7198 /* Get array */ 7199 PetscCall(VecGetArray(v, &array)); 7200 /* Get values */ 7201 if (numFields > 0) { 7202 PetscInt offset = 0, f; 7203 for (f = 0; f < numFields; ++f) { 7204 const PetscInt **perms = NULL; 7205 const PetscScalar **flips = NULL; 7206 7207 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7208 switch (mode) { 7209 case INSERT_VALUES: 7210 for (p = 0; p < numPoints; p++) { 7211 const PetscInt point = points[2 * p]; 7212 const PetscInt *perm = perms ? perms[p] : NULL; 7213 const PetscScalar *flip = flips ? flips[p] : NULL; 7214 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7215 } 7216 break; 7217 case INSERT_ALL_VALUES: 7218 for (p = 0; p < numPoints; p++) { 7219 const PetscInt point = points[2 * p]; 7220 const PetscInt *perm = perms ? perms[p] : NULL; 7221 const PetscScalar *flip = flips ? flips[p] : NULL; 7222 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7223 } 7224 break; 7225 case INSERT_BC_VALUES: 7226 for (p = 0; p < numPoints; p++) { 7227 const PetscInt point = points[2 * p]; 7228 const PetscInt *perm = perms ? perms[p] : NULL; 7229 const PetscScalar *flip = flips ? flips[p] : NULL; 7230 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7231 } 7232 break; 7233 case ADD_VALUES: 7234 for (p = 0; p < numPoints; p++) { 7235 const PetscInt point = points[2 * p]; 7236 const PetscInt *perm = perms ? perms[p] : NULL; 7237 const PetscScalar *flip = flips ? flips[p] : NULL; 7238 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7239 } 7240 break; 7241 case ADD_ALL_VALUES: 7242 for (p = 0; p < numPoints; p++) { 7243 const PetscInt point = points[2 * p]; 7244 const PetscInt *perm = perms ? perms[p] : NULL; 7245 const PetscScalar *flip = flips ? flips[p] : NULL; 7246 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7247 } 7248 break; 7249 case ADD_BC_VALUES: 7250 for (p = 0; p < numPoints; p++) { 7251 const PetscInt point = points[2 * p]; 7252 const PetscInt *perm = perms ? perms[p] : NULL; 7253 const PetscScalar *flip = flips ? flips[p] : NULL; 7254 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7255 } 7256 break; 7257 default: 7258 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7259 } 7260 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7261 } 7262 } else { 7263 PetscInt dof, off; 7264 const PetscInt **perms = NULL; 7265 const PetscScalar **flips = NULL; 7266 7267 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7268 switch (mode) { 7269 case INSERT_VALUES: 7270 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7271 const PetscInt point = points[2 * p]; 7272 const PetscInt *perm = perms ? perms[p] : NULL; 7273 const PetscScalar *flip = flips ? flips[p] : NULL; 7274 PetscCall(PetscSectionGetDof(section, point, &dof)); 7275 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7276 } 7277 break; 7278 case INSERT_ALL_VALUES: 7279 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 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(PetscSectionGetDof(section, point, &dof)); 7284 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7285 } 7286 break; 7287 case INSERT_BC_VALUES: 7288 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7289 const PetscInt point = points[2 * p]; 7290 const PetscInt *perm = perms ? perms[p] : NULL; 7291 const PetscScalar *flip = flips ? flips[p] : NULL; 7292 PetscCall(PetscSectionGetDof(section, point, &dof)); 7293 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7294 } 7295 break; 7296 case ADD_VALUES: 7297 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7298 const PetscInt point = points[2 * p]; 7299 const PetscInt *perm = perms ? perms[p] : NULL; 7300 const PetscScalar *flip = flips ? flips[p] : NULL; 7301 PetscCall(PetscSectionGetDof(section, point, &dof)); 7302 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7303 } 7304 break; 7305 case ADD_ALL_VALUES: 7306 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7307 const PetscInt point = points[2 * p]; 7308 const PetscInt *perm = perms ? perms[p] : NULL; 7309 const PetscScalar *flip = flips ? flips[p] : NULL; 7310 PetscCall(PetscSectionGetDof(section, point, &dof)); 7311 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7312 } 7313 break; 7314 case ADD_BC_VALUES: 7315 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7316 const PetscInt point = points[2 * p]; 7317 const PetscInt *perm = perms ? perms[p] : NULL; 7318 const PetscScalar *flip = flips ? flips[p] : NULL; 7319 PetscCall(PetscSectionGetDof(section, point, &dof)); 7320 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7321 } 7322 break; 7323 default: 7324 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7325 } 7326 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7327 } 7328 /* Cleanup points */ 7329 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7330 /* Cleanup array */ 7331 PetscCall(VecRestoreArray(v, &array)); 7332 PetscFunctionReturn(PETSC_SUCCESS); 7333 } 7334 7335 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7336 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7337 { 7338 PetscFunctionBegin; 7339 *contains = PETSC_TRUE; 7340 if (label) { 7341 PetscInt fdof; 7342 7343 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7344 if (!*contains) { 7345 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7346 *offset += fdof; 7347 PetscFunctionReturn(PETSC_SUCCESS); 7348 } 7349 } 7350 PetscFunctionReturn(PETSC_SUCCESS); 7351 } 7352 7353 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7354 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) 7355 { 7356 PetscSection clSection; 7357 IS clPoints; 7358 PetscScalar *array; 7359 PetscInt *points = NULL; 7360 const PetscInt *clp; 7361 PetscInt numFields, numPoints, p; 7362 PetscInt offset = 0, f; 7363 7364 PetscFunctionBeginHot; 7365 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7366 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7367 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7368 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7369 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7370 /* Get points */ 7371 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7372 /* Get array */ 7373 PetscCall(VecGetArray(v, &array)); 7374 /* Get values */ 7375 for (f = 0; f < numFields; ++f) { 7376 const PetscInt **perms = NULL; 7377 const PetscScalar **flips = NULL; 7378 PetscBool contains; 7379 7380 if (!fieldActive[f]) { 7381 for (p = 0; p < numPoints * 2; p += 2) { 7382 PetscInt fdof; 7383 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7384 offset += fdof; 7385 } 7386 continue; 7387 } 7388 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7389 switch (mode) { 7390 case INSERT_VALUES: 7391 for (p = 0; p < numPoints; p++) { 7392 const PetscInt point = points[2 * p]; 7393 const PetscInt *perm = perms ? perms[p] : NULL; 7394 const PetscScalar *flip = flips ? flips[p] : NULL; 7395 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7396 if (!contains) continue; 7397 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7398 } 7399 break; 7400 case INSERT_ALL_VALUES: 7401 for (p = 0; p < numPoints; p++) { 7402 const PetscInt point = points[2 * p]; 7403 const PetscInt *perm = perms ? perms[p] : NULL; 7404 const PetscScalar *flip = flips ? flips[p] : NULL; 7405 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7406 if (!contains) continue; 7407 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7408 } 7409 break; 7410 case INSERT_BC_VALUES: 7411 for (p = 0; p < numPoints; p++) { 7412 const PetscInt point = points[2 * p]; 7413 const PetscInt *perm = perms ? perms[p] : NULL; 7414 const PetscScalar *flip = flips ? flips[p] : NULL; 7415 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7416 if (!contains) continue; 7417 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7418 } 7419 break; 7420 case ADD_VALUES: 7421 for (p = 0; p < numPoints; p++) { 7422 const PetscInt point = points[2 * p]; 7423 const PetscInt *perm = perms ? perms[p] : NULL; 7424 const PetscScalar *flip = flips ? flips[p] : NULL; 7425 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7426 if (!contains) continue; 7427 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7428 } 7429 break; 7430 case ADD_ALL_VALUES: 7431 for (p = 0; p < numPoints; p++) { 7432 const PetscInt point = points[2 * p]; 7433 const PetscInt *perm = perms ? perms[p] : NULL; 7434 const PetscScalar *flip = flips ? flips[p] : NULL; 7435 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7436 if (!contains) continue; 7437 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7438 } 7439 break; 7440 default: 7441 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7442 } 7443 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7444 } 7445 /* Cleanup points */ 7446 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7447 /* Cleanup array */ 7448 PetscCall(VecRestoreArray(v, &array)); 7449 PetscFunctionReturn(PETSC_SUCCESS); 7450 } 7451 7452 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7453 { 7454 PetscMPIInt rank; 7455 PetscInt i, j; 7456 7457 PetscFunctionBegin; 7458 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7459 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7460 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7461 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7462 numCIndices = numCIndices ? numCIndices : numRIndices; 7463 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7464 for (i = 0; i < numRIndices; i++) { 7465 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7466 for (j = 0; j < numCIndices; j++) { 7467 #if defined(PETSC_USE_COMPLEX) 7468 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7469 #else 7470 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7471 #endif 7472 } 7473 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7474 } 7475 PetscFunctionReturn(PETSC_SUCCESS); 7476 } 7477 7478 /* 7479 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7480 7481 Input Parameters: 7482 + section - The section for this data layout 7483 . islocal - Is the section (and thus indices being requested) local or global? 7484 . point - The point contributing dofs with these indices 7485 . off - The global offset of this point 7486 . loff - The local offset of each field 7487 . setBC - The flag determining whether to include indices of boundary values 7488 . perm - A permutation of the dofs on this point, or NULL 7489 - indperm - A permutation of the entire indices array, or NULL 7490 7491 Output Parameter: 7492 . indices - Indices for dofs on this point 7493 7494 Level: developer 7495 7496 Note: The indices could be local or global, depending on the value of 'off'. 7497 */ 7498 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7499 { 7500 PetscInt dof; /* The number of unknowns on this point */ 7501 PetscInt cdof; /* The number of constraints on this point */ 7502 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7503 PetscInt cind = 0, k; 7504 7505 PetscFunctionBegin; 7506 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7507 PetscCall(PetscSectionGetDof(section, point, &dof)); 7508 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7509 if (!cdof || setBC) { 7510 for (k = 0; k < dof; ++k) { 7511 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7512 const PetscInt ind = indperm ? indperm[preind] : preind; 7513 7514 indices[ind] = off + k; 7515 } 7516 } else { 7517 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7518 for (k = 0; k < dof; ++k) { 7519 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7520 const PetscInt ind = indperm ? indperm[preind] : preind; 7521 7522 if ((cind < cdof) && (k == cdofs[cind])) { 7523 /* Insert check for returning constrained indices */ 7524 indices[ind] = -(off + k + 1); 7525 ++cind; 7526 } else { 7527 indices[ind] = off + k - (islocal ? 0 : cind); 7528 } 7529 } 7530 } 7531 *loff += dof; 7532 PetscFunctionReturn(PETSC_SUCCESS); 7533 } 7534 7535 /* 7536 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7537 7538 Input Parameters: 7539 + section - a section (global or local) 7540 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7541 . point - point within section 7542 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7543 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7544 . setBC - identify constrained (boundary condition) points via involution. 7545 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7546 . permsoff - offset 7547 - indperm - index permutation 7548 7549 Output Parameter: 7550 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7551 . indices - array to hold indices (as defined by section) of each dof associated with point 7552 7553 Notes: 7554 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7555 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7556 in the local vector. 7557 7558 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7559 significant). It is invalid to call with a global section and setBC=true. 7560 7561 Developer Note: 7562 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7563 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7564 offset could be obtained from the section instead of passing it explicitly as we do now. 7565 7566 Example: 7567 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7568 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7569 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7570 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. 7571 7572 Level: developer 7573 */ 7574 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[]) 7575 { 7576 PetscInt numFields, foff, f; 7577 7578 PetscFunctionBegin; 7579 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7580 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7581 for (f = 0, foff = 0; f < numFields; ++f) { 7582 PetscInt fdof, cfdof; 7583 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7584 PetscInt cind = 0, b; 7585 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7586 7587 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7588 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7589 if (!cfdof || setBC) { 7590 for (b = 0; b < fdof; ++b) { 7591 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7592 const PetscInt ind = indperm ? indperm[preind] : preind; 7593 7594 indices[ind] = off + foff + b; 7595 } 7596 } else { 7597 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7598 for (b = 0; b < fdof; ++b) { 7599 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7600 const PetscInt ind = indperm ? indperm[preind] : preind; 7601 7602 if ((cind < cfdof) && (b == fcdofs[cind])) { 7603 indices[ind] = -(off + foff + b + 1); 7604 ++cind; 7605 } else { 7606 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7607 } 7608 } 7609 } 7610 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7611 foffs[f] += fdof; 7612 } 7613 PetscFunctionReturn(PETSC_SUCCESS); 7614 } 7615 7616 /* 7617 This version believes the globalSection offsets for each field, rather than just the point offset 7618 7619 . foffs - The offset into 'indices' for each field, since it is segregated by field 7620 7621 Notes: 7622 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7623 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7624 */ 7625 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7626 { 7627 PetscInt numFields, foff, f; 7628 7629 PetscFunctionBegin; 7630 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7631 for (f = 0; f < numFields; ++f) { 7632 PetscInt fdof, cfdof; 7633 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7634 PetscInt cind = 0, b; 7635 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7636 7637 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7638 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7639 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7640 if (!cfdof) { 7641 for (b = 0; b < fdof; ++b) { 7642 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7643 const PetscInt ind = indperm ? indperm[preind] : preind; 7644 7645 indices[ind] = foff + b; 7646 } 7647 } else { 7648 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7649 for (b = 0; b < fdof; ++b) { 7650 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7651 const PetscInt ind = indperm ? indperm[preind] : preind; 7652 7653 if ((cind < cfdof) && (b == fcdofs[cind])) { 7654 indices[ind] = -(foff + b + 1); 7655 ++cind; 7656 } else { 7657 indices[ind] = foff + b - cind; 7658 } 7659 } 7660 } 7661 foffs[f] += fdof; 7662 } 7663 PetscFunctionReturn(PETSC_SUCCESS); 7664 } 7665 7666 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7667 { 7668 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7669 7670 PetscFunctionBegin; 7671 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7672 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7673 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7674 for (PetscInt p = 0; p < nPoints; p++) { 7675 PetscInt b = pnts[2 * p]; 7676 PetscInt bSecDof = 0, bOff; 7677 PetscInt cSecDof = 0; 7678 PetscSection indices_section; 7679 7680 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7681 if (!bSecDof) continue; 7682 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7683 indices_section = cSecDof > 0 ? cSec : section; 7684 if (numFields) { 7685 PetscInt fStart[32], fEnd[32]; 7686 7687 fStart[0] = 0; 7688 fEnd[0] = 0; 7689 for (PetscInt f = 0; f < numFields; f++) { 7690 PetscInt fDof = 0; 7691 7692 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7693 fStart[f + 1] = fStart[f] + fDof; 7694 fEnd[f + 1] = fStart[f + 1]; 7695 } 7696 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7697 // only apply permutations on one side 7698 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7699 for (PetscInt f = 0; f < numFields; f++) { 7700 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7701 } 7702 } else { 7703 PetscInt bEnd = 0; 7704 7705 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7706 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7707 7708 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7709 } 7710 } 7711 PetscFunctionReturn(PETSC_SUCCESS); 7712 } 7713 7714 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[]) 7715 { 7716 Mat cMat; 7717 PetscSection aSec, cSec; 7718 IS aIS; 7719 PetscInt aStart = -1, aEnd = -1; 7720 PetscInt sStart = -1, sEnd = -1; 7721 PetscInt cStart = -1, cEnd = -1; 7722 const PetscInt *anchors; 7723 PetscInt numFields, p; 7724 PetscInt newNumPoints = 0, newNumIndices = 0; 7725 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7726 PetscInt oldOffsets[32]; 7727 PetscInt newOffsets[32]; 7728 PetscInt oldOffsetsCopy[32]; 7729 PetscInt newOffsetsCopy[32]; 7730 PetscScalar *modMat = NULL; 7731 PetscBool anyConstrained = PETSC_FALSE; 7732 7733 PetscFunctionBegin; 7734 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7735 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7736 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7737 7738 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7739 /* if there are point-to-point constraints */ 7740 if (aSec) { 7741 PetscCall(PetscArrayzero(newOffsets, 32)); 7742 PetscCall(PetscArrayzero(oldOffsets, 32)); 7743 PetscCall(ISGetIndices(aIS, &anchors)); 7744 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7745 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7746 /* figure out how many points are going to be in the new element matrix 7747 * (we allow double counting, because it's all just going to be summed 7748 * into the global matrix anyway) */ 7749 for (p = 0; p < 2 * numPoints; p += 2) { 7750 PetscInt b = points[p]; 7751 PetscInt bDof = 0, bSecDof = 0; 7752 7753 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7754 if (!bSecDof) continue; 7755 7756 for (PetscInt f = 0; f < numFields; f++) { 7757 PetscInt fDof = 0; 7758 7759 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7760 oldOffsets[f + 1] += fDof; 7761 } 7762 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7763 if (bDof) { 7764 /* this point is constrained */ 7765 /* it is going to be replaced by its anchors */ 7766 PetscInt bOff, q; 7767 7768 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7769 for (q = 0; q < bDof; q++) { 7770 PetscInt a = anchors[bOff + q]; 7771 PetscInt aDof = 0; 7772 7773 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7774 if (aDof) { 7775 anyConstrained = PETSC_TRUE; 7776 newNumPoints += 1; 7777 } 7778 newNumIndices += aDof; 7779 for (PetscInt f = 0; f < numFields; ++f) { 7780 PetscInt fDof = 0; 7781 7782 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7783 newOffsets[f + 1] += fDof; 7784 } 7785 } 7786 } else { 7787 /* this point is not constrained */ 7788 newNumPoints++; 7789 newNumIndices += bSecDof; 7790 for (PetscInt f = 0; f < numFields; ++f) { 7791 PetscInt fDof; 7792 7793 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7794 newOffsets[f + 1] += fDof; 7795 } 7796 } 7797 } 7798 } 7799 if (!anyConstrained) { 7800 if (outNumPoints) *outNumPoints = 0; 7801 if (outNumIndices) *outNumIndices = 0; 7802 if (outPoints) *outPoints = NULL; 7803 if (outMat) *outMat = NULL; 7804 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7805 PetscFunctionReturn(PETSC_SUCCESS); 7806 } 7807 7808 if (outNumPoints) *outNumPoints = newNumPoints; 7809 if (outNumIndices) *outNumIndices = newNumIndices; 7810 7811 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7812 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7813 7814 if (!outPoints && !outMat) { 7815 if (offsets) { 7816 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7817 } 7818 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7819 PetscFunctionReturn(PETSC_SUCCESS); 7820 } 7821 7822 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7823 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7824 7825 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7826 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7827 7828 /* output arrays */ 7829 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7830 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7831 7832 // get the new Points 7833 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7834 PetscInt b = points[2 * p]; 7835 PetscInt bDof = 0, bSecDof = 0, bOff; 7836 7837 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7838 if (!bSecDof) continue; 7839 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7840 if (bDof) { 7841 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7842 for (PetscInt q = 0; q < bDof; q++) { 7843 PetscInt a = anchors[bOff + q], aDof = 0; 7844 7845 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7846 if (aDof) { 7847 newPoints[2 * newP] = a; 7848 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7849 newP++; 7850 } 7851 } 7852 } else { 7853 newPoints[2 * newP] = b; 7854 newPoints[2 * newP + 1] = points[2 * p + 1]; 7855 newP++; 7856 } 7857 } 7858 7859 if (outMat) { 7860 PetscScalar *tmpMat; 7861 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7862 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7863 7864 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7865 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7866 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7867 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7868 7869 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7870 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7871 7872 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7873 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7874 7875 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7876 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7877 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7878 // for each field, insert the anchor modification into modMat 7879 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7880 PetscInt fStart = oldOffsets[f]; 7881 PetscInt fNewStart = newOffsets[f]; 7882 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7883 PetscInt b = points[2 * p]; 7884 PetscInt bDof = 0, bSecDof = 0, bOff; 7885 7886 if (b >= sStart && b < sEnd) { 7887 if (numFields) { 7888 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7889 } else { 7890 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7891 } 7892 } 7893 if (!bSecDof) continue; 7894 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7895 if (bDof) { 7896 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7897 for (PetscInt q = 0; q < bDof; q++, newP++) { 7898 PetscInt a = anchors[bOff + q], aDof = 0; 7899 7900 if (a >= sStart && a < sEnd) { 7901 if (numFields) { 7902 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7903 } else { 7904 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7905 } 7906 } 7907 if (aDof) { 7908 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7909 for (PetscInt d = 0; d < bSecDof; d++) { 7910 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7911 } 7912 } 7913 oNew += aDof; 7914 } 7915 } else { 7916 // Insert the identity matrix in this block 7917 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7918 oNew += bSecDof; 7919 newP++; 7920 } 7921 o += bSecDof; 7922 } 7923 } 7924 7925 *outMat = modMat; 7926 7927 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7928 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7929 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7930 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7931 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7932 } 7933 PetscCall(ISRestoreIndices(aIS, &anchors)); 7934 7935 /* output */ 7936 if (outPoints) { 7937 *outPoints = newPoints; 7938 } else { 7939 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7940 } 7941 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7942 PetscFunctionReturn(PETSC_SUCCESS); 7943 } 7944 7945 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) 7946 { 7947 PetscScalar *modMat = NULL; 7948 PetscInt newNumIndices = -1; 7949 7950 PetscFunctionBegin; 7951 /* 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. 7952 modMat is that matrix C */ 7953 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7954 if (outNumIndices) *outNumIndices = newNumIndices; 7955 if (modMat) { 7956 const PetscScalar *newValues = values; 7957 7958 if (multiplyRight) { 7959 PetscScalar *newNewValues = NULL; 7960 PetscBLASInt M, N, K; 7961 PetscScalar a = 1.0, b = 0.0; 7962 7963 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); 7964 7965 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7966 PetscCall(PetscBLASIntCast(numRows, &N)); 7967 PetscCall(PetscBLASIntCast(numIndices, &K)); 7968 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7969 // row-major to column-major conversion, right multiplication becomes left multiplication 7970 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7971 numCols = newNumIndices; 7972 newValues = newNewValues; 7973 } 7974 7975 if (multiplyLeft) { 7976 PetscScalar *newNewValues = NULL; 7977 PetscBLASInt M, N, K; 7978 PetscScalar a = 1.0, b = 0.0; 7979 7980 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); 7981 7982 PetscCall(PetscBLASIntCast(numCols, &M)); 7983 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7984 PetscCall(PetscBLASIntCast(numIndices, &K)); 7985 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7986 // row-major to column-major conversion, left multiplication becomes right multiplication 7987 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7988 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7989 newValues = newNewValues; 7990 } 7991 *outValues = (PetscScalar *)newValues; 7992 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7993 } 7994 PetscFunctionReturn(PETSC_SUCCESS); 7995 } 7996 7997 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) 7998 { 7999 PetscFunctionBegin; 8000 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 8001 PetscFunctionReturn(PETSC_SUCCESS); 8002 } 8003 8004 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 8005 { 8006 /* Closure ordering */ 8007 PetscSection clSection; 8008 IS clPoints; 8009 const PetscInt *clp; 8010 PetscInt *points; 8011 PetscInt Ncl, Ni = 0; 8012 8013 PetscFunctionBeginHot; 8014 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8015 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 8016 PetscInt dof; 8017 8018 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8019 Ni += dof; 8020 } 8021 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8022 *closureSize = Ni; 8023 PetscFunctionReturn(PETSC_SUCCESS); 8024 } 8025 8026 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) 8027 { 8028 /* Closure ordering */ 8029 PetscSection clSection; 8030 IS clPoints; 8031 const PetscInt *clp; 8032 PetscInt *points; 8033 const PetscInt *clperm = NULL; 8034 /* Dof permutation and sign flips */ 8035 const PetscInt **perms[32] = {NULL}; 8036 const PetscScalar **flips[32] = {NULL}; 8037 PetscScalar *valCopy = NULL; 8038 /* Hanging node constraints */ 8039 PetscInt *pointsC = NULL; 8040 PetscScalar *valuesC = NULL; 8041 PetscInt NclC, NiC; 8042 8043 PetscInt *idx; 8044 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8045 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8046 PetscInt idxStart, idxEnd; 8047 PetscInt nRows, nCols; 8048 8049 PetscFunctionBeginHot; 8050 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8051 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8052 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8053 PetscAssertPointer(numRows, 6); 8054 PetscAssertPointer(numCols, 7); 8055 if (indices) PetscAssertPointer(indices, 8); 8056 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8057 if (values) PetscAssertPointer(values, 10); 8058 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8059 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8060 PetscCall(PetscArrayzero(offsets, 32)); 8061 /* 1) Get points in closure */ 8062 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8063 if (useClPerm) { 8064 PetscInt depth, clsize; 8065 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8066 for (clsize = 0, p = 0; p < Ncl; p++) { 8067 PetscInt dof; 8068 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8069 clsize += dof; 8070 } 8071 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8072 } 8073 /* 2) Get number of indices on these points and field offsets from section */ 8074 for (p = 0; p < Ncl * 2; p += 2) { 8075 PetscInt dof, fdof; 8076 8077 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8078 for (f = 0; f < Nf; ++f) { 8079 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8080 offsets[f + 1] += fdof; 8081 } 8082 Ni += dof; 8083 } 8084 if (*numRows == -1) *numRows = Ni; 8085 if (*numCols == -1) *numCols = Ni; 8086 nRows = *numRows; 8087 nCols = *numCols; 8088 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8089 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8090 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8091 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8092 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8093 for (f = 0; f < PetscMax(1, Nf); ++f) { 8094 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8095 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8096 /* may need to apply sign changes to the element matrix */ 8097 if (values && flips[f]) { 8098 PetscInt foffset = offsets[f]; 8099 8100 for (p = 0; p < Ncl; ++p) { 8101 PetscInt pnt = points[2 * p], fdof; 8102 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8103 8104 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8105 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8106 if (flip) { 8107 PetscInt i, j, k; 8108 8109 if (!valCopy) { 8110 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8111 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8112 *values = valCopy; 8113 } 8114 for (i = 0; i < fdof; ++i) { 8115 PetscScalar fval = flip[i]; 8116 8117 if (multiplyRight) { 8118 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8119 } 8120 if (multiplyLeft) { 8121 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8122 } 8123 } 8124 } 8125 foffset += fdof; 8126 } 8127 } 8128 } 8129 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8130 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8131 if (NclC) { 8132 if (multiplyRight) *numCols = NiC; 8133 if (multiplyLeft) *numRows = NiC; 8134 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8135 for (f = 0; f < PetscMax(1, Nf); ++f) { 8136 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8137 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8138 } 8139 for (f = 0; f < PetscMax(1, Nf); ++f) { 8140 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8141 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8142 } 8143 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8144 Ncl = NclC; 8145 Ni = NiC; 8146 points = pointsC; 8147 if (values) *values = valuesC; 8148 } 8149 /* 5) Calculate indices */ 8150 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8151 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8152 if (Nf) { 8153 PetscInt idxOff; 8154 PetscBool useFieldOffsets; 8155 8156 if (outOffsets) { 8157 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8158 } 8159 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8160 if (useFieldOffsets) { 8161 for (p = 0; p < Ncl; ++p) { 8162 const PetscInt pnt = points[p * 2]; 8163 8164 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8165 } 8166 } else { 8167 for (p = 0; p < Ncl; ++p) { 8168 const PetscInt pnt = points[p * 2]; 8169 8170 if (pnt < idxStart || pnt >= idxEnd) continue; 8171 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8172 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8173 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8174 * global section. */ 8175 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8176 } 8177 } 8178 } else { 8179 PetscInt off = 0, idxOff; 8180 8181 for (p = 0; p < Ncl; ++p) { 8182 const PetscInt pnt = points[p * 2]; 8183 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8184 8185 if (pnt < idxStart || pnt >= idxEnd) continue; 8186 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8187 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8188 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8189 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8190 } 8191 } 8192 /* 6) Cleanup */ 8193 for (f = 0; f < PetscMax(1, Nf); ++f) { 8194 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8195 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8196 } 8197 if (NclC) { 8198 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8199 } else { 8200 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8201 } 8202 8203 if (indices) *indices = idx; 8204 PetscFunctionReturn(PETSC_SUCCESS); 8205 } 8206 8207 /*@C 8208 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8209 8210 Not collective 8211 8212 Input Parameters: 8213 + dm - The `DM` 8214 . section - The `PetscSection` describing the points (a local section) 8215 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8216 . point - The point defining the closure 8217 - useClPerm - Use the closure point permutation if available 8218 8219 Output Parameters: 8220 + numIndices - The number of dof indices in the closure of point with the input sections 8221 . indices - The dof indices 8222 . outOffsets - Array to write the field offsets into, or `NULL` 8223 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8224 8225 Level: advanced 8226 8227 Notes: 8228 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8229 8230 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8231 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8232 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8233 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8234 indices (with the above semantics) are implied. 8235 8236 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8237 `PetscSection`, `DMGetGlobalSection()` 8238 @*/ 8239 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8240 { 8241 PetscInt numRows = -1, numCols = -1; 8242 8243 PetscFunctionBeginHot; 8244 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8245 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8246 *numIndices = numRows; 8247 PetscFunctionReturn(PETSC_SUCCESS); 8248 } 8249 8250 /*@C 8251 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8252 8253 Not collective 8254 8255 Input Parameters: 8256 + dm - The `DM` 8257 . section - The `PetscSection` describing the points (a local section) 8258 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8259 . point - The point defining the closure 8260 - useClPerm - Use the closure point permutation if available 8261 8262 Output Parameters: 8263 + numIndices - The number of dof indices in the closure of point with the input sections 8264 . indices - The dof indices 8265 . outOffsets - Array to write the field offsets into, or `NULL` 8266 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8267 8268 Level: advanced 8269 8270 Notes: 8271 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8272 8273 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8274 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8275 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8276 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8277 indices (with the above semantics) are implied. 8278 8279 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8280 @*/ 8281 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8282 { 8283 PetscFunctionBegin; 8284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8285 PetscAssertPointer(indices, 7); 8286 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8287 PetscFunctionReturn(PETSC_SUCCESS); 8288 } 8289 8290 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8291 { 8292 DM_Plex *mesh = (DM_Plex *)dm->data; 8293 PetscInt *indices; 8294 PetscInt numIndices; 8295 const PetscScalar *valuesOrig = values; 8296 PetscErrorCode ierr; 8297 8298 PetscFunctionBegin; 8299 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8300 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8301 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8302 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8303 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8304 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8305 8306 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8307 8308 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8309 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8310 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8311 if (ierr) { 8312 PetscMPIInt rank; 8313 8314 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8315 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8316 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8317 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8318 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8319 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8320 } 8321 if (mesh->printFEM > 1) { 8322 PetscInt i; 8323 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8324 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8325 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8326 } 8327 8328 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8329 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8330 PetscFunctionReturn(PETSC_SUCCESS); 8331 } 8332 8333 /*@C 8334 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8335 8336 Not collective 8337 8338 Input Parameters: 8339 + dm - The `DM` 8340 . section - The section describing the layout in `v`, or `NULL` to use the default section 8341 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8342 . A - The matrix 8343 . point - The point in the `DM` 8344 . values - The array of values 8345 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8346 8347 Level: intermediate 8348 8349 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8350 @*/ 8351 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8352 { 8353 PetscFunctionBegin; 8354 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8355 PetscFunctionReturn(PETSC_SUCCESS); 8356 } 8357 8358 /*@C 8359 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8360 8361 Not collective 8362 8363 Input Parameters: 8364 + dmRow - The `DM` for the row fields 8365 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8366 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8367 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8368 . dmCol - The `DM` for the column fields 8369 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8370 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8371 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8372 . A - The matrix 8373 . point - The point in the `DM` 8374 . values - The array of values 8375 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8376 8377 Level: intermediate 8378 8379 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8380 @*/ 8381 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) 8382 { 8383 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8384 PetscInt *indicesRow, *indicesCol; 8385 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8386 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8387 8388 PetscErrorCode ierr; 8389 8390 PetscFunctionBegin; 8391 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8392 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8393 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8394 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8395 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8396 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8397 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8398 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8399 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8400 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8401 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8402 8403 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8404 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8405 valuesV1 = valuesV0; 8406 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8407 valuesV2 = valuesV1; 8408 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8409 8410 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8411 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8412 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8413 if (ierr) { 8414 PetscMPIInt rank; 8415 8416 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8417 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8418 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8419 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8420 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8421 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8422 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8423 } 8424 8425 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8426 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8427 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8428 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8429 PetscFunctionReturn(PETSC_SUCCESS); 8430 } 8431 8432 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8433 { 8434 DM_Plex *mesh = (DM_Plex *)dmf->data; 8435 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8436 PetscInt *cpoints = NULL; 8437 PetscInt *findices, *cindices; 8438 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8439 PetscInt foffsets[32], coffsets[32]; 8440 DMPolytopeType ct; 8441 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8442 PetscErrorCode ierr; 8443 8444 PetscFunctionBegin; 8445 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8446 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8447 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8448 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8449 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8450 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8451 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8452 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8453 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8454 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8455 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8456 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8457 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8458 PetscCall(PetscArrayzero(foffsets, 32)); 8459 PetscCall(PetscArrayzero(coffsets, 32)); 8460 /* Column indices */ 8461 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8462 maxFPoints = numCPoints; 8463 /* Compress out points not in the section */ 8464 /* TODO: Squeeze out points with 0 dof as well */ 8465 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8466 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8467 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8468 cpoints[q * 2] = cpoints[p]; 8469 cpoints[q * 2 + 1] = cpoints[p + 1]; 8470 ++q; 8471 } 8472 } 8473 numCPoints = q; 8474 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8475 PetscInt fdof; 8476 8477 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8478 if (!dof) continue; 8479 for (f = 0; f < numFields; ++f) { 8480 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8481 coffsets[f + 1] += fdof; 8482 } 8483 numCIndices += dof; 8484 } 8485 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8486 /* Row indices */ 8487 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8488 { 8489 DMPlexTransform tr; 8490 DMPolytopeType *rct; 8491 PetscInt *rsize, *rcone, *rornt, Nt; 8492 8493 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8494 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8495 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8496 numSubcells = rsize[Nt - 1]; 8497 PetscCall(DMPlexTransformDestroy(&tr)); 8498 } 8499 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8500 for (r = 0, q = 0; r < numSubcells; ++r) { 8501 /* TODO Map from coarse to fine cells */ 8502 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8503 /* Compress out points not in the section */ 8504 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8505 for (p = 0; p < numFPoints * 2; p += 2) { 8506 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8507 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8508 if (!dof) continue; 8509 for (s = 0; s < q; ++s) 8510 if (fpoints[p] == ftotpoints[s * 2]) break; 8511 if (s < q) continue; 8512 ftotpoints[q * 2] = fpoints[p]; 8513 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8514 ++q; 8515 } 8516 } 8517 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8518 } 8519 numFPoints = q; 8520 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8521 PetscInt fdof; 8522 8523 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8524 if (!dof) continue; 8525 for (f = 0; f < numFields; ++f) { 8526 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8527 foffsets[f + 1] += fdof; 8528 } 8529 numFIndices += dof; 8530 } 8531 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8532 8533 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8534 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8535 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8536 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8537 if (numFields) { 8538 const PetscInt **permsF[32] = {NULL}; 8539 const PetscInt **permsC[32] = {NULL}; 8540 8541 for (f = 0; f < numFields; f++) { 8542 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8543 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8544 } 8545 for (p = 0; p < numFPoints; p++) { 8546 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8547 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8548 } 8549 for (p = 0; p < numCPoints; p++) { 8550 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8551 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8552 } 8553 for (f = 0; f < numFields; f++) { 8554 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8555 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8556 } 8557 } else { 8558 const PetscInt **permsF = NULL; 8559 const PetscInt **permsC = NULL; 8560 8561 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8562 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8563 for (p = 0, off = 0; p < numFPoints; p++) { 8564 const PetscInt *perm = permsF ? permsF[p] : NULL; 8565 8566 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8567 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8568 } 8569 for (p = 0, off = 0; p < numCPoints; p++) { 8570 const PetscInt *perm = permsC ? permsC[p] : NULL; 8571 8572 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8573 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8574 } 8575 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8576 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8577 } 8578 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8579 /* TODO: flips */ 8580 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8581 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8582 if (ierr) { 8583 PetscMPIInt rank; 8584 8585 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8586 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8587 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8588 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8589 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8590 } 8591 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8592 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8593 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8594 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8595 PetscFunctionReturn(PETSC_SUCCESS); 8596 } 8597 8598 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8599 { 8600 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8601 PetscInt *cpoints = NULL; 8602 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8603 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8604 DMPolytopeType ct; 8605 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8606 8607 PetscFunctionBegin; 8608 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8609 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8610 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8611 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8612 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8613 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8614 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8615 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8616 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8617 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8618 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8619 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8620 /* Column indices */ 8621 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8622 maxFPoints = numCPoints; 8623 /* Compress out points not in the section */ 8624 /* TODO: Squeeze out points with 0 dof as well */ 8625 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8626 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8627 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8628 cpoints[q * 2] = cpoints[p]; 8629 cpoints[q * 2 + 1] = cpoints[p + 1]; 8630 ++q; 8631 } 8632 } 8633 numCPoints = q; 8634 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8635 PetscInt fdof; 8636 8637 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8638 if (!dof) continue; 8639 for (f = 0; f < numFields; ++f) { 8640 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8641 coffsets[f + 1] += fdof; 8642 } 8643 numCIndices += dof; 8644 } 8645 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8646 /* Row indices */ 8647 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8648 { 8649 DMPlexTransform tr; 8650 DMPolytopeType *rct; 8651 PetscInt *rsize, *rcone, *rornt, Nt; 8652 8653 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8654 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8655 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8656 numSubcells = rsize[Nt - 1]; 8657 PetscCall(DMPlexTransformDestroy(&tr)); 8658 } 8659 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8660 for (r = 0, q = 0; r < numSubcells; ++r) { 8661 /* TODO Map from coarse to fine cells */ 8662 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8663 /* Compress out points not in the section */ 8664 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8665 for (p = 0; p < numFPoints * 2; p += 2) { 8666 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8667 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8668 if (!dof) continue; 8669 for (s = 0; s < q; ++s) 8670 if (fpoints[p] == ftotpoints[s * 2]) break; 8671 if (s < q) continue; 8672 ftotpoints[q * 2] = fpoints[p]; 8673 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8674 ++q; 8675 } 8676 } 8677 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8678 } 8679 numFPoints = q; 8680 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8681 PetscInt fdof; 8682 8683 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8684 if (!dof) continue; 8685 for (f = 0; f < numFields; ++f) { 8686 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8687 foffsets[f + 1] += fdof; 8688 } 8689 numFIndices += dof; 8690 } 8691 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8692 8693 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8694 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8695 if (numFields) { 8696 const PetscInt **permsF[32] = {NULL}; 8697 const PetscInt **permsC[32] = {NULL}; 8698 8699 for (f = 0; f < numFields; f++) { 8700 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8701 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8702 } 8703 for (p = 0; p < numFPoints; p++) { 8704 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8705 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8706 } 8707 for (p = 0; p < numCPoints; p++) { 8708 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8709 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8710 } 8711 for (f = 0; f < numFields; f++) { 8712 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8713 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8714 } 8715 } else { 8716 const PetscInt **permsF = NULL; 8717 const PetscInt **permsC = NULL; 8718 8719 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8720 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8721 for (p = 0, off = 0; p < numFPoints; p++) { 8722 const PetscInt *perm = permsF ? permsF[p] : NULL; 8723 8724 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8725 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8726 } 8727 for (p = 0, off = 0; p < numCPoints; p++) { 8728 const PetscInt *perm = permsC ? permsC[p] : NULL; 8729 8730 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8731 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8732 } 8733 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8734 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8735 } 8736 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8737 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8738 PetscFunctionReturn(PETSC_SUCCESS); 8739 } 8740 8741 /*@ 8742 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8743 8744 Input Parameter: 8745 . dm - The `DMPLEX` object 8746 8747 Output Parameter: 8748 . cellHeight - The height of a cell 8749 8750 Level: developer 8751 8752 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8753 @*/ 8754 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8755 { 8756 DM_Plex *mesh = (DM_Plex *)dm->data; 8757 8758 PetscFunctionBegin; 8759 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8760 PetscAssertPointer(cellHeight, 2); 8761 *cellHeight = mesh->vtkCellHeight; 8762 PetscFunctionReturn(PETSC_SUCCESS); 8763 } 8764 8765 /*@ 8766 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8767 8768 Input Parameters: 8769 + dm - The `DMPLEX` object 8770 - cellHeight - The height of a cell 8771 8772 Level: developer 8773 8774 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8775 @*/ 8776 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8777 { 8778 DM_Plex *mesh = (DM_Plex *)dm->data; 8779 8780 PetscFunctionBegin; 8781 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8782 mesh->vtkCellHeight = cellHeight; 8783 PetscFunctionReturn(PETSC_SUCCESS); 8784 } 8785 8786 /*@ 8787 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8788 8789 Input Parameters: 8790 + dm - The `DMPLEX` object 8791 - ct - The `DMPolytopeType` of the cell 8792 8793 Output Parameters: 8794 + start - The first cell of this type, or `NULL` 8795 - end - The upper bound on this celltype, or `NULL` 8796 8797 Level: advanced 8798 8799 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8800 @*/ 8801 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end) 8802 { 8803 DM_Plex *mesh = (DM_Plex *)dm->data; 8804 DMLabel label; 8805 PetscInt pStart, pEnd; 8806 8807 PetscFunctionBegin; 8808 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8809 if (start) { 8810 PetscAssertPointer(start, 3); 8811 *start = 0; 8812 } 8813 if (end) { 8814 PetscAssertPointer(end, 4); 8815 *end = 0; 8816 } 8817 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8818 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8819 if (mesh->tr) { 8820 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8821 } else { 8822 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8823 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8824 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8825 } 8826 PetscFunctionReturn(PETSC_SUCCESS); 8827 } 8828 8829 /*@ 8830 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8831 8832 Input Parameters: 8833 + dm - The `DMPLEX` object 8834 - depth - The depth for the given point stratum 8835 8836 Output Parameter: 8837 . gsize - The global number of points in the stratum 8838 8839 Level: advanced 8840 8841 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8842 @*/ 8843 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8844 { 8845 PetscSF sf; 8846 const PetscInt *leaves; 8847 PetscInt Nl, loc, start, end, lsize = 0; 8848 8849 PetscFunctionBegin; 8850 PetscCall(DMGetPointSF(dm, &sf)); 8851 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8852 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8853 for (PetscInt p = start; p < end; ++p) { 8854 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8855 if (loc < 0) ++lsize; 8856 } 8857 PetscCallMPI(MPI_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8858 PetscFunctionReturn(PETSC_SUCCESS); 8859 } 8860 8861 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8862 { 8863 PetscSection section, globalSection; 8864 PetscInt *numbers, p; 8865 8866 PetscFunctionBegin; 8867 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8868 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8869 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8870 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8871 PetscCall(PetscSectionSetUp(section)); 8872 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8873 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8874 for (p = pStart; p < pEnd; ++p) { 8875 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8876 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8877 else numbers[p - pStart] += shift; 8878 } 8879 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8880 if (globalSize) { 8881 PetscLayout layout; 8882 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8883 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8884 PetscCall(PetscLayoutDestroy(&layout)); 8885 } 8886 PetscCall(PetscSectionDestroy(§ion)); 8887 PetscCall(PetscSectionDestroy(&globalSection)); 8888 PetscFunctionReturn(PETSC_SUCCESS); 8889 } 8890 8891 /*@ 8892 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8893 8894 Input Parameters: 8895 + dm - The `DMPLEX` object 8896 - includeAll - Whether to include all cells, or just the simplex and box cells 8897 8898 Output Parameter: 8899 . globalCellNumbers - Global cell numbers for all cells on this process 8900 8901 Level: developer 8902 8903 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8904 @*/ 8905 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8906 { 8907 PetscInt cellHeight, cStart, cEnd; 8908 8909 PetscFunctionBegin; 8910 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8911 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8912 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8913 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8914 PetscFunctionReturn(PETSC_SUCCESS); 8915 } 8916 8917 /*@ 8918 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8919 8920 Input Parameter: 8921 . dm - The `DMPLEX` object 8922 8923 Output Parameter: 8924 . globalCellNumbers - Global cell numbers for all cells on this process 8925 8926 Level: developer 8927 8928 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8929 @*/ 8930 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8931 { 8932 DM_Plex *mesh = (DM_Plex *)dm->data; 8933 8934 PetscFunctionBegin; 8935 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8936 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8937 *globalCellNumbers = mesh->globalCellNumbers; 8938 PetscFunctionReturn(PETSC_SUCCESS); 8939 } 8940 8941 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8942 { 8943 PetscInt vStart, vEnd; 8944 8945 PetscFunctionBegin; 8946 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8947 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8948 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8949 PetscFunctionReturn(PETSC_SUCCESS); 8950 } 8951 8952 /*@ 8953 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8954 8955 Input Parameter: 8956 . dm - The `DMPLEX` object 8957 8958 Output Parameter: 8959 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8960 8961 Level: developer 8962 8963 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8964 @*/ 8965 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8966 { 8967 DM_Plex *mesh = (DM_Plex *)dm->data; 8968 8969 PetscFunctionBegin; 8970 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8971 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8972 *globalVertexNumbers = mesh->globalVertexNumbers; 8973 PetscFunctionReturn(PETSC_SUCCESS); 8974 } 8975 8976 /*@ 8977 DMPlexCreatePointNumbering - Create a global numbering for all points. 8978 8979 Collective 8980 8981 Input Parameter: 8982 . dm - The `DMPLEX` object 8983 8984 Output Parameter: 8985 . globalPointNumbers - Global numbers for all points on this process 8986 8987 Level: developer 8988 8989 Notes: 8990 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8991 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8992 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8993 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8994 8995 The partitioned mesh is 8996 ``` 8997 (2)--0--(3)--1--(4) (1)--0--(2) 8998 ``` 8999 and its global numbering is 9000 ``` 9001 (3)--0--(4)--1--(5)--2--(6) 9002 ``` 9003 Then the global numbering is provided as 9004 ``` 9005 [0] Number of indices in set 5 9006 [0] 0 0 9007 [0] 1 1 9008 [0] 2 3 9009 [0] 3 4 9010 [0] 4 -6 9011 [1] Number of indices in set 3 9012 [1] 0 2 9013 [1] 1 5 9014 [1] 2 6 9015 ``` 9016 9017 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9018 @*/ 9019 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 9020 { 9021 IS nums[4]; 9022 PetscInt depths[4], gdepths[4], starts[4]; 9023 PetscInt depth, d, shift = 0; 9024 PetscBool empty = PETSC_FALSE; 9025 9026 PetscFunctionBegin; 9027 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9028 PetscCall(DMPlexGetDepth(dm, &depth)); 9029 // For unstratified meshes use dim instead of depth 9030 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9031 // If any stratum is empty, we must mark all empty 9032 for (d = 0; d <= depth; ++d) { 9033 PetscInt end; 9034 9035 depths[d] = depth - d; 9036 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9037 if (!(starts[d] - end)) empty = PETSC_TRUE; 9038 } 9039 if (empty) 9040 for (d = 0; d <= depth; ++d) { 9041 depths[d] = -1; 9042 starts[d] = -1; 9043 } 9044 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9045 PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9046 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]); 9047 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9048 for (d = 0; d <= depth; ++d) { 9049 PetscInt pStart, pEnd, gsize; 9050 9051 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9052 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9053 shift += gsize; 9054 } 9055 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9056 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9057 PetscFunctionReturn(PETSC_SUCCESS); 9058 } 9059 9060 /*@ 9061 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9062 9063 Collective 9064 9065 Input Parameter: 9066 . dm - The `DMPLEX` object 9067 9068 Output Parameter: 9069 . globalEdgeNumbers - Global numbers for all edges on this process 9070 9071 Level: developer 9072 9073 Notes: 9074 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). 9075 9076 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9077 @*/ 9078 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9079 { 9080 PetscSF sf; 9081 PetscInt eStart, eEnd; 9082 9083 PetscFunctionBegin; 9084 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9085 PetscCall(DMGetPointSF(dm, &sf)); 9086 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9087 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9088 PetscFunctionReturn(PETSC_SUCCESS); 9089 } 9090 9091 /*@ 9092 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9093 9094 Input Parameter: 9095 . dm - The `DMPLEX` object 9096 9097 Output Parameter: 9098 . ranks - The rank field 9099 9100 Options Database Key: 9101 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9102 9103 Level: intermediate 9104 9105 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9106 @*/ 9107 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9108 { 9109 DM rdm; 9110 PetscFE fe; 9111 PetscScalar *r; 9112 PetscMPIInt rank; 9113 DMPolytopeType ct; 9114 PetscInt dim, cStart, cEnd, c; 9115 PetscBool simplex; 9116 9117 PetscFunctionBeginUser; 9118 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9119 PetscAssertPointer(ranks, 2); 9120 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9121 PetscCall(DMClone(dm, &rdm)); 9122 PetscCall(DMGetDimension(rdm, &dim)); 9123 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9124 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9125 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9126 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9127 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9128 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9129 PetscCall(PetscFEDestroy(&fe)); 9130 PetscCall(DMCreateDS(rdm)); 9131 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9132 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9133 PetscCall(VecGetArray(*ranks, &r)); 9134 for (c = cStart; c < cEnd; ++c) { 9135 PetscScalar *lr; 9136 9137 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9138 if (lr) *lr = rank; 9139 } 9140 PetscCall(VecRestoreArray(*ranks, &r)); 9141 PetscCall(DMDestroy(&rdm)); 9142 PetscFunctionReturn(PETSC_SUCCESS); 9143 } 9144 9145 /*@ 9146 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9147 9148 Input Parameters: 9149 + dm - The `DMPLEX` 9150 - label - The `DMLabel` 9151 9152 Output Parameter: 9153 . val - The label value field 9154 9155 Options Database Key: 9156 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9157 9158 Level: intermediate 9159 9160 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9161 @*/ 9162 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9163 { 9164 DM rdm, plex; 9165 Vec lval; 9166 PetscSection section; 9167 PetscFE fe; 9168 PetscScalar *v; 9169 PetscInt dim, pStart, pEnd, p, cStart; 9170 DMPolytopeType ct; 9171 char name[PETSC_MAX_PATH_LEN]; 9172 const char *lname, *prefix; 9173 9174 PetscFunctionBeginUser; 9175 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9176 PetscAssertPointer(label, 2); 9177 PetscAssertPointer(val, 3); 9178 PetscCall(DMClone(dm, &rdm)); 9179 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9180 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9181 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9182 PetscCall(DMDestroy(&plex)); 9183 PetscCall(DMGetDimension(rdm, &dim)); 9184 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9185 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9186 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9187 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9188 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9189 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9190 PetscCall(PetscFEDestroy(&fe)); 9191 PetscCall(DMCreateDS(rdm)); 9192 PetscCall(DMCreateGlobalVector(rdm, val)); 9193 PetscCall(DMCreateLocalVector(rdm, &lval)); 9194 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9195 PetscCall(DMGetLocalSection(rdm, §ion)); 9196 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9197 PetscCall(VecGetArray(lval, &v)); 9198 for (p = pStart; p < pEnd; ++p) { 9199 PetscInt cval, dof, off; 9200 9201 PetscCall(PetscSectionGetDof(section, p, &dof)); 9202 if (!dof) continue; 9203 PetscCall(DMLabelGetValue(label, p, &cval)); 9204 PetscCall(PetscSectionGetOffset(section, p, &off)); 9205 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9206 } 9207 PetscCall(VecRestoreArray(lval, &v)); 9208 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9209 PetscCall(VecDestroy(&lval)); 9210 PetscCall(DMDestroy(&rdm)); 9211 PetscFunctionReturn(PETSC_SUCCESS); 9212 } 9213 9214 /*@ 9215 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9216 9217 Input Parameter: 9218 . dm - The `DMPLEX` object 9219 9220 Level: developer 9221 9222 Notes: 9223 This is a useful diagnostic when creating meshes programmatically. 9224 9225 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9226 9227 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9228 @*/ 9229 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9230 { 9231 PetscSection coneSection, supportSection; 9232 const PetscInt *cone, *support; 9233 PetscInt coneSize, c, supportSize, s; 9234 PetscInt pStart, pEnd, p, pp, csize, ssize; 9235 PetscBool storagecheck = PETSC_TRUE; 9236 9237 PetscFunctionBegin; 9238 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9239 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9240 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9241 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9242 /* Check that point p is found in the support of its cone points, and vice versa */ 9243 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9244 for (p = pStart; p < pEnd; ++p) { 9245 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9246 PetscCall(DMPlexGetCone(dm, p, &cone)); 9247 for (c = 0; c < coneSize; ++c) { 9248 PetscBool dup = PETSC_FALSE; 9249 PetscInt d; 9250 for (d = c - 1; d >= 0; --d) { 9251 if (cone[c] == cone[d]) { 9252 dup = PETSC_TRUE; 9253 break; 9254 } 9255 } 9256 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9257 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9258 for (s = 0; s < supportSize; ++s) { 9259 if (support[s] == p) break; 9260 } 9261 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9262 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9263 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9264 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9265 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9266 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9267 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9268 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]); 9269 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9270 } 9271 } 9272 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9273 if (p != pp) { 9274 storagecheck = PETSC_FALSE; 9275 continue; 9276 } 9277 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9278 PetscCall(DMPlexGetSupport(dm, p, &support)); 9279 for (s = 0; s < supportSize; ++s) { 9280 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9281 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9282 for (c = 0; c < coneSize; ++c) { 9283 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9284 if (cone[c] != pp) { 9285 c = 0; 9286 break; 9287 } 9288 if (cone[c] == p) break; 9289 } 9290 if (c >= coneSize) { 9291 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9292 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9293 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9294 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9295 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9296 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9297 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9298 } 9299 } 9300 } 9301 if (storagecheck) { 9302 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9303 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9304 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9305 } 9306 PetscFunctionReturn(PETSC_SUCCESS); 9307 } 9308 9309 /* 9310 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. 9311 */ 9312 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9313 { 9314 DMPolytopeType cct; 9315 PetscInt ptpoints[4]; 9316 const PetscInt *cone, *ccone, *ptcone; 9317 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9318 9319 PetscFunctionBegin; 9320 *unsplit = 0; 9321 switch (ct) { 9322 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9323 ptpoints[npt++] = c; 9324 break; 9325 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9326 PetscCall(DMPlexGetCone(dm, c, &cone)); 9327 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9328 for (cp = 0; cp < coneSize; ++cp) { 9329 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9330 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9331 } 9332 break; 9333 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9334 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9335 PetscCall(DMPlexGetCone(dm, c, &cone)); 9336 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9337 for (cp = 0; cp < coneSize; ++cp) { 9338 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9339 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9340 for (ccp = 0; ccp < cconeSize; ++ccp) { 9341 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9342 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9343 PetscInt p; 9344 for (p = 0; p < npt; ++p) 9345 if (ptpoints[p] == ccone[ccp]) break; 9346 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9347 } 9348 } 9349 } 9350 break; 9351 default: 9352 break; 9353 } 9354 for (pt = 0; pt < npt; ++pt) { 9355 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9356 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9357 } 9358 PetscFunctionReturn(PETSC_SUCCESS); 9359 } 9360 9361 /*@ 9362 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9363 9364 Input Parameters: 9365 + dm - The `DMPLEX` object 9366 - cellHeight - Normally 0 9367 9368 Level: developer 9369 9370 Notes: 9371 This is a useful diagnostic when creating meshes programmatically. 9372 Currently applicable only to homogeneous simplex or tensor meshes. 9373 9374 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9375 9376 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9377 @*/ 9378 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9379 { 9380 DMPlexInterpolatedFlag interp; 9381 DMPolytopeType ct; 9382 PetscInt vStart, vEnd, cStart, cEnd, c; 9383 9384 PetscFunctionBegin; 9385 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9386 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9387 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9388 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9389 for (c = cStart; c < cEnd; ++c) { 9390 PetscInt *closure = NULL; 9391 PetscInt coneSize, closureSize, cl, Nv = 0; 9392 9393 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9394 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9395 if (interp == DMPLEX_INTERPOLATED_FULL) { 9396 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9397 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)); 9398 } 9399 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9400 for (cl = 0; cl < closureSize * 2; cl += 2) { 9401 const PetscInt p = closure[cl]; 9402 if ((p >= vStart) && (p < vEnd)) ++Nv; 9403 } 9404 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9405 /* Special Case: Tensor faces with identified vertices */ 9406 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9407 PetscInt unsplit; 9408 9409 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9410 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9411 } 9412 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)); 9413 } 9414 PetscFunctionReturn(PETSC_SUCCESS); 9415 } 9416 9417 /*@ 9418 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9419 9420 Collective 9421 9422 Input Parameters: 9423 + dm - The `DMPLEX` object 9424 - cellHeight - Normally 0 9425 9426 Level: developer 9427 9428 Notes: 9429 This is a useful diagnostic when creating meshes programmatically. 9430 This routine is only relevant for meshes that are fully interpolated across all ranks. 9431 It will error out if a partially interpolated mesh is given on some rank. 9432 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9433 9434 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9435 9436 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9437 @*/ 9438 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9439 { 9440 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9441 DMPlexInterpolatedFlag interpEnum; 9442 9443 PetscFunctionBegin; 9444 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9445 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9446 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9447 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9448 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9449 PetscFunctionReturn(PETSC_SUCCESS); 9450 } 9451 9452 PetscCall(DMGetDimension(dm, &dim)); 9453 PetscCall(DMPlexGetDepth(dm, &depth)); 9454 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9455 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9456 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9457 for (c = cStart; c < cEnd; ++c) { 9458 const PetscInt *cone, *ornt, *faceSizes, *faces; 9459 const DMPolytopeType *faceTypes; 9460 DMPolytopeType ct; 9461 PetscInt numFaces, coneSize, f; 9462 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9463 9464 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9465 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9466 if (unsplit) continue; 9467 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9468 PetscCall(DMPlexGetCone(dm, c, &cone)); 9469 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9470 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9471 for (cl = 0; cl < closureSize * 2; cl += 2) { 9472 const PetscInt p = closure[cl]; 9473 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9474 } 9475 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9476 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); 9477 for (f = 0; f < numFaces; ++f) { 9478 DMPolytopeType fct; 9479 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9480 9481 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9482 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9483 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9484 const PetscInt p = fclosure[cl]; 9485 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9486 } 9487 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]); 9488 for (v = 0; v < fnumCorners; ++v) { 9489 if (fclosure[v] != faces[fOff + v]) { 9490 PetscInt v1; 9491 9492 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9493 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9494 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9495 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9496 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9497 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]); 9498 } 9499 } 9500 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9501 fOff += faceSizes[f]; 9502 } 9503 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9504 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9505 } 9506 } 9507 PetscFunctionReturn(PETSC_SUCCESS); 9508 } 9509 9510 /*@ 9511 DMPlexCheckGeometry - Check the geometry of mesh cells 9512 9513 Input Parameter: 9514 . dm - The `DMPLEX` object 9515 9516 Level: developer 9517 9518 Notes: 9519 This is a useful diagnostic when creating meshes programmatically. 9520 9521 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9522 9523 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9524 @*/ 9525 PetscErrorCode DMPlexCheckGeometry(DM dm) 9526 { 9527 Vec coordinates; 9528 PetscReal detJ, J[9], refVol = 1.0; 9529 PetscReal vol; 9530 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9531 9532 PetscFunctionBegin; 9533 PetscCall(DMGetDimension(dm, &dim)); 9534 PetscCall(DMGetCoordinateDim(dm, &dE)); 9535 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9536 PetscCall(DMPlexGetDepth(dm, &depth)); 9537 for (d = 0; d < dim; ++d) refVol *= 2.0; 9538 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9539 /* Make sure local coordinates are created, because that step is collective */ 9540 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9541 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9542 for (c = cStart; c < cEnd; ++c) { 9543 DMPolytopeType ct; 9544 PetscInt unsplit; 9545 PetscBool ignoreZeroVol = PETSC_FALSE; 9546 9547 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9548 switch (ct) { 9549 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9550 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9551 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9552 ignoreZeroVol = PETSC_TRUE; 9553 break; 9554 default: 9555 break; 9556 } 9557 switch (ct) { 9558 case DM_POLYTOPE_TRI_PRISM: 9559 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9560 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9561 case DM_POLYTOPE_PYRAMID: 9562 continue; 9563 default: 9564 break; 9565 } 9566 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9567 if (unsplit) continue; 9568 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9569 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); 9570 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9571 /* This should work with periodicity since DG coordinates should be used */ 9572 if (depth > 1) { 9573 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9574 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); 9575 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9576 } 9577 } 9578 PetscFunctionReturn(PETSC_SUCCESS); 9579 } 9580 9581 /*@ 9582 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9583 9584 Collective 9585 9586 Input Parameters: 9587 + dm - The `DMPLEX` object 9588 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9589 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9590 9591 Level: developer 9592 9593 Notes: 9594 This is mainly intended for debugging/testing purposes. 9595 9596 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9597 9598 Extra roots can come from periodic cuts, where additional points appear on the boundary 9599 9600 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9601 @*/ 9602 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9603 { 9604 PetscInt l, nleaves, nroots, overlap; 9605 const PetscInt *locals; 9606 const PetscSFNode *remotes; 9607 PetscBool distributed; 9608 MPI_Comm comm; 9609 PetscMPIInt rank; 9610 9611 PetscFunctionBegin; 9612 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9613 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9614 else pointSF = dm->sf; 9615 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9616 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9617 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9618 { 9619 PetscMPIInt mpiFlag; 9620 9621 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9622 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9623 } 9624 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9625 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9626 if (!distributed) { 9627 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); 9628 PetscFunctionReturn(PETSC_SUCCESS); 9629 } 9630 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); 9631 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9632 9633 /* Check SF graph is compatible with DMPlex chart */ 9634 { 9635 PetscInt pStart, pEnd, maxLeaf; 9636 9637 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9638 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9639 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9640 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9641 } 9642 9643 /* Check there are no cells in interface */ 9644 if (!overlap) { 9645 PetscInt cellHeight, cStart, cEnd; 9646 9647 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9648 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9649 for (l = 0; l < nleaves; ++l) { 9650 const PetscInt point = locals ? locals[l] : l; 9651 9652 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9653 } 9654 } 9655 9656 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9657 { 9658 const PetscInt *rootdegree; 9659 9660 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9661 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9662 for (l = 0; l < nleaves; ++l) { 9663 const PetscInt point = locals ? locals[l] : l; 9664 const PetscInt *cone; 9665 PetscInt coneSize, c, idx; 9666 9667 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9668 PetscCall(DMPlexGetCone(dm, point, &cone)); 9669 for (c = 0; c < coneSize; ++c) { 9670 if (!rootdegree[cone[c]]) { 9671 if (locals) { 9672 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9673 } else { 9674 idx = (cone[c] < nleaves) ? cone[c] : -1; 9675 } 9676 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9677 } 9678 } 9679 } 9680 } 9681 PetscFunctionReturn(PETSC_SUCCESS); 9682 } 9683 9684 /*@ 9685 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9686 9687 Collective 9688 9689 Input Parameter: 9690 . dm - The `DMPLEX` object 9691 9692 Level: developer 9693 9694 Notes: 9695 This is mainly intended for debugging/testing purposes. 9696 9697 Other cell types which are disconnected would be caught by the symmetry and face checks. 9698 9699 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9700 9701 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9702 @*/ 9703 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9704 { 9705 PetscInt pStart, pEnd, vStart, vEnd; 9706 9707 PetscFunctionBegin; 9708 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9709 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9710 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9711 for (PetscInt v = vStart; v < vEnd; ++v) { 9712 PetscInt suppSize; 9713 9714 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9715 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9716 } 9717 PetscFunctionReturn(PETSC_SUCCESS); 9718 } 9719 9720 /*@ 9721 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9722 9723 Input Parameter: 9724 . dm - The `DMPLEX` object 9725 9726 Level: developer 9727 9728 Notes: 9729 This is a useful diagnostic when creating meshes programmatically. 9730 9731 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9732 9733 Currently does not include `DMPlexCheckCellShape()`. 9734 9735 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9736 @*/ 9737 PetscErrorCode DMPlexCheck(DM dm) 9738 { 9739 PetscInt cellHeight; 9740 9741 PetscFunctionBegin; 9742 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9743 PetscCall(DMPlexCheckSymmetry(dm)); 9744 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9745 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9746 PetscCall(DMPlexCheckGeometry(dm)); 9747 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9748 PetscCall(DMPlexCheckInterfaceCones(dm)); 9749 PetscCall(DMPlexCheckOrphanVertices(dm)); 9750 PetscFunctionReturn(PETSC_SUCCESS); 9751 } 9752 9753 typedef struct cell_stats { 9754 PetscReal min, max, sum, squaresum; 9755 PetscInt count; 9756 } cell_stats_t; 9757 9758 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9759 { 9760 PetscInt i, N = *len; 9761 9762 for (i = 0; i < N; i++) { 9763 cell_stats_t *A = (cell_stats_t *)a; 9764 cell_stats_t *B = (cell_stats_t *)b; 9765 9766 B->min = PetscMin(A->min, B->min); 9767 B->max = PetscMax(A->max, B->max); 9768 B->sum += A->sum; 9769 B->squaresum += A->squaresum; 9770 B->count += A->count; 9771 } 9772 } 9773 9774 /*@ 9775 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9776 9777 Collective 9778 9779 Input Parameters: 9780 + dm - The `DMPLEX` object 9781 . output - If true, statistics will be displayed on `stdout` 9782 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9783 9784 Level: developer 9785 9786 Notes: 9787 This is mainly intended for debugging/testing purposes. 9788 9789 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9790 9791 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9792 @*/ 9793 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9794 { 9795 DM dmCoarse; 9796 cell_stats_t stats, globalStats; 9797 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9798 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9799 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9800 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9801 PetscMPIInt rank, size; 9802 9803 PetscFunctionBegin; 9804 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9805 stats.min = PETSC_MAX_REAL; 9806 stats.max = PETSC_MIN_REAL; 9807 stats.sum = stats.squaresum = 0.; 9808 stats.count = 0; 9809 9810 PetscCallMPI(MPI_Comm_size(comm, &size)); 9811 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9812 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9813 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9814 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9815 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9816 for (c = cStart; c < cEnd; c++) { 9817 PetscInt i; 9818 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9819 9820 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9821 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9822 for (i = 0; i < PetscSqr(cdim); ++i) { 9823 frobJ += J[i] * J[i]; 9824 frobInvJ += invJ[i] * invJ[i]; 9825 } 9826 cond2 = frobJ * frobInvJ; 9827 cond = PetscSqrtReal(cond2); 9828 9829 stats.min = PetscMin(stats.min, cond); 9830 stats.max = PetscMax(stats.max, cond); 9831 stats.sum += cond; 9832 stats.squaresum += cond2; 9833 stats.count++; 9834 if (output && cond > limit) { 9835 PetscSection coordSection; 9836 Vec coordsLocal; 9837 PetscScalar *coords = NULL; 9838 PetscInt Nv, d, clSize, cl, *closure = NULL; 9839 9840 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9841 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9842 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9843 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9844 for (i = 0; i < Nv / cdim; ++i) { 9845 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9846 for (d = 0; d < cdim; ++d) { 9847 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9848 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9849 } 9850 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9851 } 9852 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9853 for (cl = 0; cl < clSize * 2; cl += 2) { 9854 const PetscInt edge = closure[cl]; 9855 9856 if ((edge >= eStart) && (edge < eEnd)) { 9857 PetscReal len; 9858 9859 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9860 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9861 } 9862 } 9863 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9864 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9865 } 9866 } 9867 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9868 9869 if (size > 1) { 9870 PetscMPIInt blockLengths[2] = {4, 1}; 9871 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9872 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9873 MPI_Op statReduce; 9874 9875 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9876 PetscCallMPI(MPI_Type_commit(&statType)); 9877 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9878 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9879 PetscCallMPI(MPI_Op_free(&statReduce)); 9880 PetscCallMPI(MPI_Type_free(&statType)); 9881 } else { 9882 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9883 } 9884 if (rank == 0) { 9885 count = globalStats.count; 9886 min = globalStats.min; 9887 max = globalStats.max; 9888 mean = globalStats.sum / globalStats.count; 9889 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9890 } 9891 9892 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)); 9893 PetscCall(PetscFree2(J, invJ)); 9894 9895 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9896 if (dmCoarse) { 9897 PetscBool isplex; 9898 9899 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9900 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9901 } 9902 PetscFunctionReturn(PETSC_SUCCESS); 9903 } 9904 9905 /*@ 9906 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9907 orthogonal quality below given tolerance. 9908 9909 Collective 9910 9911 Input Parameters: 9912 + dm - The `DMPLEX` object 9913 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9914 - atol - [0, 1] Absolute tolerance for tagging cells. 9915 9916 Output Parameters: 9917 + OrthQual - `Vec` containing orthogonal quality per cell 9918 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9919 9920 Options Database Keys: 9921 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9922 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9923 9924 Level: intermediate 9925 9926 Notes: 9927 Orthogonal quality is given by the following formula\: 9928 9929 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9930 9931 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 9932 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9933 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9934 calculating the cosine of the angle between these vectors. 9935 9936 Orthogonal quality ranges from 1 (best) to 0 (worst). 9937 9938 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9939 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9940 9941 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9942 9943 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9944 @*/ 9945 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9946 { 9947 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9948 PetscInt *idx; 9949 PetscScalar *oqVals; 9950 const PetscScalar *cellGeomArr, *faceGeomArr; 9951 PetscReal *ci, *fi, *Ai; 9952 MPI_Comm comm; 9953 Vec cellgeom, facegeom; 9954 DM dmFace, dmCell; 9955 IS glob; 9956 ISLocalToGlobalMapping ltog; 9957 PetscViewer vwr; 9958 9959 PetscFunctionBegin; 9960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9961 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9962 PetscAssertPointer(OrthQual, 4); 9963 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9964 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9965 PetscCall(DMGetDimension(dm, &nc)); 9966 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9967 { 9968 DMPlexInterpolatedFlag interpFlag; 9969 9970 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9971 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9972 PetscMPIInt rank; 9973 9974 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9975 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9976 } 9977 } 9978 if (OrthQualLabel) { 9979 PetscAssertPointer(OrthQualLabel, 5); 9980 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9981 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9982 } else { 9983 *OrthQualLabel = NULL; 9984 } 9985 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9986 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9987 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9988 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9989 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9990 PetscCall(VecCreate(comm, OrthQual)); 9991 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9992 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9993 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9994 PetscCall(VecSetUp(*OrthQual)); 9995 PetscCall(ISDestroy(&glob)); 9996 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9997 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9998 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9999 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 10000 PetscCall(VecGetDM(cellgeom, &dmCell)); 10001 PetscCall(VecGetDM(facegeom, &dmFace)); 10002 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 10003 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 10004 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 10005 PetscInt cellarr[2], *adj = NULL; 10006 PetscScalar *cArr, *fArr; 10007 PetscReal minvalc = 1.0, minvalf = 1.0; 10008 PetscFVCellGeom *cg; 10009 10010 idx[cellIter] = cell - cStart; 10011 cellarr[0] = cell; 10012 /* Make indexing into cellGeom easier */ 10013 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10014 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10015 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10016 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10017 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10018 PetscInt i; 10019 const PetscInt neigh = adj[cellneigh]; 10020 PetscReal normci = 0, normfi = 0, normai = 0; 10021 PetscFVCellGeom *cgneigh; 10022 PetscFVFaceGeom *fg; 10023 10024 /* Don't count ourselves in the neighbor list */ 10025 if (neigh == cell) continue; 10026 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10027 cellarr[1] = neigh; 10028 { 10029 PetscInt numcovpts; 10030 const PetscInt *covpts; 10031 10032 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10033 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10034 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10035 } 10036 10037 /* Compute c_i, f_i and their norms */ 10038 for (i = 0; i < nc; i++) { 10039 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10040 fi[i] = fg->centroid[i] - cg->centroid[i]; 10041 Ai[i] = fg->normal[i]; 10042 normci += PetscPowReal(ci[i], 2); 10043 normfi += PetscPowReal(fi[i], 2); 10044 normai += PetscPowReal(Ai[i], 2); 10045 } 10046 normci = PetscSqrtReal(normci); 10047 normfi = PetscSqrtReal(normfi); 10048 normai = PetscSqrtReal(normai); 10049 10050 /* Normalize and compute for each face-cell-normal pair */ 10051 for (i = 0; i < nc; i++) { 10052 ci[i] = ci[i] / normci; 10053 fi[i] = fi[i] / normfi; 10054 Ai[i] = Ai[i] / normai; 10055 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10056 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10057 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10058 } 10059 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10060 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10061 } 10062 PetscCall(PetscFree(adj)); 10063 PetscCall(PetscFree2(cArr, fArr)); 10064 /* Defer to cell if they're equal */ 10065 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10066 if (OrthQualLabel) { 10067 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10068 } 10069 } 10070 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10071 PetscCall(VecAssemblyBegin(*OrthQual)); 10072 PetscCall(VecAssemblyEnd(*OrthQual)); 10073 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10074 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10075 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10076 if (OrthQualLabel) { 10077 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10078 } 10079 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10080 PetscCall(PetscViewerDestroy(&vwr)); 10081 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10082 PetscFunctionReturn(PETSC_SUCCESS); 10083 } 10084 10085 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10086 * interpolator construction */ 10087 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10088 { 10089 PetscSection section, newSection, gsection; 10090 PetscSF sf; 10091 PetscBool hasConstraints, ghasConstraints; 10092 10093 PetscFunctionBegin; 10094 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10095 PetscAssertPointer(odm, 2); 10096 PetscCall(DMGetLocalSection(dm, §ion)); 10097 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10098 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10099 if (!ghasConstraints) { 10100 PetscCall(PetscObjectReference((PetscObject)dm)); 10101 *odm = dm; 10102 PetscFunctionReturn(PETSC_SUCCESS); 10103 } 10104 PetscCall(DMClone(dm, odm)); 10105 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10106 PetscCall(DMGetLocalSection(*odm, &newSection)); 10107 PetscCall(DMGetPointSF(*odm, &sf)); 10108 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10109 PetscCall(DMSetGlobalSection(*odm, gsection)); 10110 PetscCall(PetscSectionDestroy(&gsection)); 10111 PetscFunctionReturn(PETSC_SUCCESS); 10112 } 10113 10114 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10115 { 10116 DM dmco, dmfo; 10117 Mat interpo; 10118 Vec rscale; 10119 Vec cglobalo, clocal; 10120 Vec fglobal, fglobalo, flocal; 10121 PetscBool regular; 10122 10123 PetscFunctionBegin; 10124 PetscCall(DMGetFullDM(dmc, &dmco)); 10125 PetscCall(DMGetFullDM(dmf, &dmfo)); 10126 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10127 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10128 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10129 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10130 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10131 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10132 PetscCall(VecSet(cglobalo, 0.)); 10133 PetscCall(VecSet(clocal, 0.)); 10134 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10135 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10136 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10137 PetscCall(VecSet(fglobal, 0.)); 10138 PetscCall(VecSet(fglobalo, 0.)); 10139 PetscCall(VecSet(flocal, 0.)); 10140 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10141 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10142 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10143 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10144 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10145 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10146 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10147 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10148 *shift = fglobal; 10149 PetscCall(VecDestroy(&flocal)); 10150 PetscCall(VecDestroy(&fglobalo)); 10151 PetscCall(VecDestroy(&clocal)); 10152 PetscCall(VecDestroy(&cglobalo)); 10153 PetscCall(VecDestroy(&rscale)); 10154 PetscCall(MatDestroy(&interpo)); 10155 PetscCall(DMDestroy(&dmfo)); 10156 PetscCall(DMDestroy(&dmco)); 10157 PetscFunctionReturn(PETSC_SUCCESS); 10158 } 10159 10160 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10161 { 10162 PetscObject shifto; 10163 Vec shift; 10164 10165 PetscFunctionBegin; 10166 if (!interp) { 10167 Vec rscale; 10168 10169 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10170 PetscCall(VecDestroy(&rscale)); 10171 } else { 10172 PetscCall(PetscObjectReference((PetscObject)interp)); 10173 } 10174 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10175 if (!shifto) { 10176 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10177 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10178 shifto = (PetscObject)shift; 10179 PetscCall(VecDestroy(&shift)); 10180 } 10181 shift = (Vec)shifto; 10182 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10183 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10184 PetscCall(MatDestroy(&interp)); 10185 PetscFunctionReturn(PETSC_SUCCESS); 10186 } 10187 10188 /* Pointwise interpolation 10189 Just code FEM for now 10190 u^f = I u^c 10191 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10192 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10193 I_{ij} = psi^f_i phi^c_j 10194 */ 10195 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10196 { 10197 PetscSection gsc, gsf; 10198 PetscInt m, n; 10199 void *ctx; 10200 DM cdm; 10201 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10202 10203 PetscFunctionBegin; 10204 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10205 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10206 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10207 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10208 10209 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10210 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10211 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10212 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10213 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10214 10215 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10216 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10217 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10218 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10219 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10220 if (scaling) { 10221 /* Use naive scaling */ 10222 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10223 } 10224 PetscFunctionReturn(PETSC_SUCCESS); 10225 } 10226 10227 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10228 { 10229 VecScatter ctx; 10230 10231 PetscFunctionBegin; 10232 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10233 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10234 PetscCall(VecScatterDestroy(&ctx)); 10235 PetscFunctionReturn(PETSC_SUCCESS); 10236 } 10237 10238 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[]) 10239 { 10240 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10241 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10242 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10243 } 10244 10245 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10246 { 10247 DM dmc; 10248 PetscDS ds; 10249 Vec ones, locmass; 10250 IS cellIS; 10251 PetscFormKey key; 10252 PetscInt depth; 10253 10254 PetscFunctionBegin; 10255 PetscCall(DMClone(dm, &dmc)); 10256 PetscCall(DMCopyDisc(dm, dmc)); 10257 PetscCall(DMGetDS(dmc, &ds)); 10258 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10259 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10260 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10261 else PetscCall(DMGetLocalVector(dm, &locmass)); 10262 PetscCall(DMGetLocalVector(dm, &ones)); 10263 PetscCall(DMPlexGetDepth(dm, &depth)); 10264 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10265 PetscCall(VecSet(locmass, 0.0)); 10266 PetscCall(VecSet(ones, 1.0)); 10267 key.label = NULL; 10268 key.value = 0; 10269 key.field = 0; 10270 key.part = 0; 10271 PetscCall(DMPlexComputeJacobianActionByKey(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10272 PetscCall(ISDestroy(&cellIS)); 10273 if (mass) { 10274 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10275 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10276 } 10277 PetscCall(DMRestoreLocalVector(dm, &ones)); 10278 if (lmass) *lmass = locmass; 10279 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10280 PetscCall(DMDestroy(&dmc)); 10281 PetscFunctionReturn(PETSC_SUCCESS); 10282 } 10283 10284 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10285 { 10286 PetscSection gsc, gsf; 10287 PetscInt m, n; 10288 void *ctx; 10289 DM cdm; 10290 PetscBool regular; 10291 10292 PetscFunctionBegin; 10293 if (dmFine == dmCoarse) { 10294 DM dmc; 10295 PetscDS ds; 10296 PetscWeakForm wf; 10297 Vec u; 10298 IS cellIS; 10299 PetscFormKey key; 10300 PetscInt depth; 10301 10302 PetscCall(DMClone(dmFine, &dmc)); 10303 PetscCall(DMCopyDisc(dmFine, dmc)); 10304 PetscCall(DMGetDS(dmc, &ds)); 10305 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10306 PetscCall(PetscWeakFormClear(wf)); 10307 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10308 PetscCall(DMCreateMatrix(dmc, mass)); 10309 PetscCall(DMGetLocalVector(dmc, &u)); 10310 PetscCall(DMPlexGetDepth(dmc, &depth)); 10311 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10312 PetscCall(MatZeroEntries(*mass)); 10313 key.label = NULL; 10314 key.value = 0; 10315 key.field = 0; 10316 key.part = 0; 10317 PetscCall(DMPlexComputeJacobianByKey(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10318 PetscCall(ISDestroy(&cellIS)); 10319 PetscCall(DMRestoreLocalVector(dmc, &u)); 10320 PetscCall(DMDestroy(&dmc)); 10321 } else { 10322 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10323 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10324 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10325 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10326 10327 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10328 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10329 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10330 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10331 10332 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10333 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10334 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10335 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10336 } 10337 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10338 PetscFunctionReturn(PETSC_SUCCESS); 10339 } 10340 10341 /*@ 10342 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10343 10344 Input Parameter: 10345 . dm - The `DMPLEX` object 10346 10347 Output Parameter: 10348 . regular - The flag 10349 10350 Level: intermediate 10351 10352 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10353 @*/ 10354 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10355 { 10356 PetscFunctionBegin; 10357 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10358 PetscAssertPointer(regular, 2); 10359 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10360 PetscFunctionReturn(PETSC_SUCCESS); 10361 } 10362 10363 /*@ 10364 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10365 10366 Input Parameters: 10367 + dm - The `DMPLEX` object 10368 - regular - The flag 10369 10370 Level: intermediate 10371 10372 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10373 @*/ 10374 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10375 { 10376 PetscFunctionBegin; 10377 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10378 ((DM_Plex *)dm->data)->regularRefinement = regular; 10379 PetscFunctionReturn(PETSC_SUCCESS); 10380 } 10381 10382 /*@ 10383 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10384 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10385 10386 Not Collective 10387 10388 Input Parameter: 10389 . dm - The `DMPLEX` object 10390 10391 Output Parameters: 10392 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10393 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10394 10395 Level: intermediate 10396 10397 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10398 @*/ 10399 PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS) 10400 { 10401 DM_Plex *plex = (DM_Plex *)dm->data; 10402 10403 PetscFunctionBegin; 10404 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10405 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10406 if (anchorSection) *anchorSection = plex->anchorSection; 10407 if (anchorIS) *anchorIS = plex->anchorIS; 10408 PetscFunctionReturn(PETSC_SUCCESS); 10409 } 10410 10411 /*@ 10412 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10413 10414 Collective 10415 10416 Input Parameters: 10417 + dm - The `DMPLEX` object 10418 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10419 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10420 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10421 10422 Level: intermediate 10423 10424 Notes: 10425 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10426 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10427 combination of other points' degrees of freedom. 10428 10429 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10430 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10431 10432 The reference counts of `anchorSection` and `anchorIS` are incremented. 10433 10434 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10435 @*/ 10436 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10437 { 10438 DM_Plex *plex = (DM_Plex *)dm->data; 10439 PetscMPIInt result; 10440 10441 PetscFunctionBegin; 10442 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10443 if (anchorSection) { 10444 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10445 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10446 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10447 } 10448 if (anchorIS) { 10449 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10450 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10451 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10452 } 10453 10454 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10455 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10456 plex->anchorSection = anchorSection; 10457 10458 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10459 PetscCall(ISDestroy(&plex->anchorIS)); 10460 plex->anchorIS = anchorIS; 10461 10462 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10463 PetscInt size, a, pStart, pEnd; 10464 const PetscInt *anchors; 10465 10466 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10467 PetscCall(ISGetLocalSize(anchorIS, &size)); 10468 PetscCall(ISGetIndices(anchorIS, &anchors)); 10469 for (a = 0; a < size; a++) { 10470 PetscInt p; 10471 10472 p = anchors[a]; 10473 if (p >= pStart && p < pEnd) { 10474 PetscInt dof; 10475 10476 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10477 if (dof) { 10478 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10479 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10480 } 10481 } 10482 } 10483 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10484 } 10485 /* reset the generic constraints */ 10486 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10487 PetscFunctionReturn(PETSC_SUCCESS); 10488 } 10489 10490 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10491 { 10492 PetscSection anchorSection; 10493 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10494 10495 PetscFunctionBegin; 10496 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10497 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10498 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10499 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10500 if (numFields) { 10501 PetscInt f; 10502 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10503 10504 for (f = 0; f < numFields; f++) { 10505 PetscInt numComp; 10506 10507 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10508 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10509 } 10510 } 10511 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10512 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10513 pStart = PetscMax(pStart, sStart); 10514 pEnd = PetscMin(pEnd, sEnd); 10515 pEnd = PetscMax(pStart, pEnd); 10516 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10517 for (p = pStart; p < pEnd; p++) { 10518 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10519 if (dof) { 10520 PetscCall(PetscSectionGetDof(section, p, &dof)); 10521 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10522 for (f = 0; f < numFields; f++) { 10523 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10524 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10525 } 10526 } 10527 } 10528 PetscCall(PetscSectionSetUp(*cSec)); 10529 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10530 PetscFunctionReturn(PETSC_SUCCESS); 10531 } 10532 10533 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10534 { 10535 PetscSection aSec; 10536 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10537 const PetscInt *anchors; 10538 PetscInt numFields, f; 10539 IS aIS; 10540 MatType mtype; 10541 PetscBool iscuda, iskokkos; 10542 10543 PetscFunctionBegin; 10544 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10545 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10546 PetscCall(PetscSectionGetStorageSize(section, &n)); 10547 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10548 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10549 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10550 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10551 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10552 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10553 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10554 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10555 else mtype = MATSEQAIJ; 10556 PetscCall(MatSetType(*cMat, mtype)); 10557 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10558 PetscCall(ISGetIndices(aIS, &anchors)); 10559 /* cSec will be a subset of aSec and section */ 10560 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10561 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10562 PetscCall(PetscMalloc1(m + 1, &i)); 10563 i[0] = 0; 10564 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10565 for (p = pStart; p < pEnd; p++) { 10566 PetscInt rDof, rOff, r; 10567 10568 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10569 if (!rDof) continue; 10570 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10571 if (numFields) { 10572 for (f = 0; f < numFields; f++) { 10573 annz = 0; 10574 for (r = 0; r < rDof; r++) { 10575 a = anchors[rOff + r]; 10576 if (a < sStart || a >= sEnd) continue; 10577 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10578 annz += aDof; 10579 } 10580 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10581 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10582 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10583 } 10584 } else { 10585 annz = 0; 10586 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10587 for (q = 0; q < dof; q++) { 10588 a = anchors[rOff + q]; 10589 if (a < sStart || a >= sEnd) continue; 10590 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10591 annz += aDof; 10592 } 10593 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10594 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10595 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10596 } 10597 } 10598 nnz = i[m]; 10599 PetscCall(PetscMalloc1(nnz, &j)); 10600 offset = 0; 10601 for (p = pStart; p < pEnd; p++) { 10602 if (numFields) { 10603 for (f = 0; f < numFields; f++) { 10604 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10605 for (q = 0; q < dof; q++) { 10606 PetscInt rDof, rOff, r; 10607 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10608 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10609 for (r = 0; r < rDof; r++) { 10610 PetscInt s; 10611 10612 a = anchors[rOff + r]; 10613 if (a < sStart || a >= sEnd) continue; 10614 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10615 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10616 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10617 } 10618 } 10619 } 10620 } else { 10621 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10622 for (q = 0; q < dof; q++) { 10623 PetscInt rDof, rOff, r; 10624 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10625 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10626 for (r = 0; r < rDof; r++) { 10627 PetscInt s; 10628 10629 a = anchors[rOff + r]; 10630 if (a < sStart || a >= sEnd) continue; 10631 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10632 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10633 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10634 } 10635 } 10636 } 10637 } 10638 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10639 PetscCall(PetscFree(i)); 10640 PetscCall(PetscFree(j)); 10641 PetscCall(ISRestoreIndices(aIS, &anchors)); 10642 PetscFunctionReturn(PETSC_SUCCESS); 10643 } 10644 10645 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10646 { 10647 DM_Plex *plex = (DM_Plex *)dm->data; 10648 PetscSection anchorSection, section, cSec; 10649 Mat cMat; 10650 10651 PetscFunctionBegin; 10652 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10653 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10654 if (anchorSection) { 10655 PetscInt Nf; 10656 10657 PetscCall(DMGetLocalSection(dm, §ion)); 10658 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10659 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10660 PetscCall(DMGetNumFields(dm, &Nf)); 10661 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10662 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10663 PetscCall(PetscSectionDestroy(&cSec)); 10664 PetscCall(MatDestroy(&cMat)); 10665 } 10666 PetscFunctionReturn(PETSC_SUCCESS); 10667 } 10668 10669 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10670 { 10671 IS subis; 10672 PetscSection section, subsection; 10673 10674 PetscFunctionBegin; 10675 PetscCall(DMGetLocalSection(dm, §ion)); 10676 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10677 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10678 /* Create subdomain */ 10679 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10680 /* Create submodel */ 10681 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10682 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10683 PetscCall(DMSetLocalSection(*subdm, subsection)); 10684 PetscCall(PetscSectionDestroy(&subsection)); 10685 PetscCall(DMCopyDisc(dm, *subdm)); 10686 /* Create map from submodel to global model */ 10687 if (is) { 10688 PetscSection sectionGlobal, subsectionGlobal; 10689 IS spIS; 10690 const PetscInt *spmap; 10691 PetscInt *subIndices; 10692 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10693 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10694 10695 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10696 PetscCall(ISGetIndices(spIS, &spmap)); 10697 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10698 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10699 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10700 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10701 for (p = pStart; p < pEnd; ++p) { 10702 PetscInt gdof, pSubSize = 0; 10703 10704 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10705 if (gdof > 0) { 10706 for (f = 0; f < Nf; ++f) { 10707 PetscInt fdof, fcdof; 10708 10709 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10710 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10711 pSubSize += fdof - fcdof; 10712 } 10713 subSize += pSubSize; 10714 if (pSubSize) { 10715 if (bs < 0) { 10716 bs = pSubSize; 10717 } else if (bs != pSubSize) { 10718 /* Layout does not admit a pointwise block size */ 10719 bs = 1; 10720 } 10721 } 10722 } 10723 } 10724 /* Must have same blocksize on all procs (some might have no points) */ 10725 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10726 bsLocal[1] = bs; 10727 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10728 if (bsMinMax[0] != bsMinMax[1]) { 10729 bs = 1; 10730 } else { 10731 bs = bsMinMax[0]; 10732 } 10733 PetscCall(PetscMalloc1(subSize, &subIndices)); 10734 for (p = pStart; p < pEnd; ++p) { 10735 PetscInt gdof, goff; 10736 10737 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10738 if (gdof > 0) { 10739 const PetscInt point = spmap[p]; 10740 10741 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10742 for (f = 0; f < Nf; ++f) { 10743 PetscInt fdof, fcdof, fc, f2, poff = 0; 10744 10745 /* Can get rid of this loop by storing field information in the global section */ 10746 for (f2 = 0; f2 < f; ++f2) { 10747 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10748 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10749 poff += fdof - fcdof; 10750 } 10751 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10752 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10753 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10754 } 10755 } 10756 } 10757 PetscCall(ISRestoreIndices(spIS, &spmap)); 10758 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10759 if (bs > 1) { 10760 /* We need to check that the block size does not come from non-contiguous fields */ 10761 PetscInt i, j, set = 1; 10762 for (i = 0; i < subSize; i += bs) { 10763 for (j = 0; j < bs; ++j) { 10764 if (subIndices[i + j] != subIndices[i] + j) { 10765 set = 0; 10766 break; 10767 } 10768 } 10769 } 10770 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10771 } 10772 /* Attach nullspace */ 10773 for (f = 0; f < Nf; ++f) { 10774 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10775 if ((*subdm)->nullspaceConstructors[f]) break; 10776 } 10777 if (f < Nf) { 10778 MatNullSpace nullSpace; 10779 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10780 10781 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10782 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10783 } 10784 } 10785 PetscFunctionReturn(PETSC_SUCCESS); 10786 } 10787 10788 /*@ 10789 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10790 10791 Input Parameters: 10792 + dm - The `DM` 10793 - dummy - unused argument 10794 10795 Options Database Key: 10796 . -dm_plex_monitor_throughput - Activate the monitor 10797 10798 Level: developer 10799 10800 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10801 @*/ 10802 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10803 { 10804 PetscLogHandler default_handler; 10805 10806 PetscFunctionBegin; 10807 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10808 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10809 if (default_handler) { 10810 PetscLogEvent event; 10811 PetscEventPerfInfo eventInfo; 10812 PetscLogDouble cellRate, flopRate; 10813 PetscInt cStart, cEnd, Nf, N; 10814 const char *name; 10815 10816 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10817 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10818 PetscCall(DMGetNumFields(dm, &Nf)); 10819 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10820 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10821 N = (cEnd - cStart) * Nf * eventInfo.count; 10822 flopRate = eventInfo.flops / eventInfo.time; 10823 cellRate = N / eventInfo.time; 10824 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)); 10825 } else { 10826 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."); 10827 } 10828 PetscFunctionReturn(PETSC_SUCCESS); 10829 } 10830