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