1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_CreateBoxSFC, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 /* Logging support */ 18 PetscLogEvent DMPLEX_DistributionView, DMPLEX_DistributionLoad; 19 20 PetscBool Plexcite = PETSC_FALSE; 21 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 22 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 23 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 24 "journal = {SIAM Journal on Scientific Computing},\n" 25 "volume = {38},\n" 26 "number = {5},\n" 27 "pages = {S143--S155},\n" 28 "eprint = {http://arxiv.org/abs/1506.07749},\n" 29 "doi = {10.1137/15M1026092},\n" 30 "year = {2016},\n" 31 "petsc_uses={DMPlex},\n}\n"; 32 33 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 34 35 /*@ 36 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 37 38 Input Parameter: 39 . dm - The `DMPLEX` object 40 41 Output Parameter: 42 . simplex - Flag checking for a simplex 43 44 Level: intermediate 45 46 Note: 47 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 48 If the mesh has no cells, this returns `PETSC_FALSE`. 49 50 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 51 @*/ 52 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 53 { 54 DMPolytopeType ct; 55 PetscInt cStart, cEnd; 56 57 PetscFunctionBegin; 58 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 59 if (cEnd <= cStart) { 60 *simplex = PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 64 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 65 PetscFunctionReturn(PETSC_SUCCESS); 66 } 67 68 /*@ 69 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 70 71 Input Parameters: 72 + dm - The `DMPLEX` object 73 - height - The cell height in the Plex, 0 is the default 74 75 Output Parameters: 76 + cStart - The first "normal" cell, pass `NULL` if not needed 77 - cEnd - The upper bound on "normal" cells, pass `NULL` if not needed 78 79 Level: developer 80 81 Note: 82 This function requires that tensor cells are ordered last. 83 84 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 85 @*/ 86 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PeOp PetscInt *cStart, PeOp PetscInt *cEnd) 87 { 88 DMLabel ctLabel; 89 IS valueIS; 90 const PetscInt *ctypes; 91 PetscBool found = PETSC_FALSE; 92 PetscInt Nct, cS = PETSC_INT_MAX, cE = 0; 93 94 PetscFunctionBegin; 95 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 96 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 97 PetscCall(ISGetLocalSize(valueIS, &Nct)); 98 PetscCall(ISGetIndices(valueIS, &ctypes)); 99 for (PetscInt t = 0; t < Nct; ++t) { 100 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 101 PetscInt ctS, ctE, ht; 102 103 if (ct == DM_POLYTOPE_UNKNOWN) { 104 // If any cells are not typed, just use all cells 105 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 106 break; 107 } 108 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 109 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 110 if (ctS >= ctE) continue; 111 // Check that a point has the right height 112 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 113 if (ht != height) continue; 114 cS = PetscMin(cS, ctS); 115 cE = PetscMax(cE, ctE); 116 found = PETSC_TRUE; 117 } 118 if (!Nct || !found) cS = cE = 0; 119 PetscCall(ISDestroy(&valueIS)); 120 // Reset label for fast lookup 121 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 122 if (cStart) *cStart = cS; 123 if (cEnd) *cEnd = cE; 124 PetscFunctionReturn(PETSC_SUCCESS); 125 } 126 127 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 128 { 129 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 130 PetscInt *sStart, *sEnd; 131 PetscViewerVTKFieldType *ft; 132 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 133 DMLabel depthLabel, ctLabel; 134 135 PetscFunctionBegin; 136 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 137 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 138 PetscCall(DMGetCoordinateDim(dm, &cdim)); 139 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 140 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 141 if (field >= 0) { 142 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 143 } else { 144 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 145 } 146 147 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 148 PetscCall(DMPlexGetDepth(dm, &depth)); 149 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 150 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 151 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 152 const DMPolytopeType ict = (DMPolytopeType)c; 153 PetscInt dep; 154 155 if (ict == DM_POLYTOPE_FV_GHOST) continue; 156 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 157 if (pStart >= 0) { 158 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 159 if (dep != depth - cellHeight) continue; 160 } 161 if (field >= 0) { 162 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 163 } else { 164 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 165 } 166 } 167 168 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 169 *types = 0; 170 171 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 172 if (globalvcdof[c]) ++(*types); 173 } 174 175 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 176 t = 0; 177 if (globalvcdof[DM_NUM_POLYTOPES]) { 178 sStart[t] = vStart; 179 sEnd[t] = vEnd; 180 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 181 ++t; 182 } 183 184 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 185 if (globalvcdof[c]) { 186 const DMPolytopeType ict = (DMPolytopeType)c; 187 188 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 189 sStart[t] = cStart; 190 sEnd[t] = cEnd; 191 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 192 ++t; 193 } 194 } 195 196 if (!*types) { 197 if (field >= 0) { 198 const char *fieldname; 199 200 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 201 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 202 } else { 203 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 204 } 205 } 206 207 *ssStart = sStart; 208 *ssEnd = sEnd; 209 *sft = ft; 210 PetscFunctionReturn(PETSC_SUCCESS); 211 } 212 213 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 214 { 215 PetscFunctionBegin; 216 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 217 PetscFunctionReturn(PETSC_SUCCESS); 218 } 219 220 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 221 { 222 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 223 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 224 225 PetscFunctionBegin; 226 *ft = PETSC_VTK_INVALID; 227 PetscCall(DMGetCoordinateDim(dm, &cdim)); 228 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 229 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 230 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 231 if (field >= 0) { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 234 } else { 235 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 236 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 237 } 238 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 239 if (globalvcdof[0]) { 240 *sStart = vStart; 241 *sEnd = vEnd; 242 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 243 else *ft = PETSC_VTK_POINT_FIELD; 244 } else if (globalvcdof[1]) { 245 *sStart = cStart; 246 *sEnd = cEnd; 247 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 248 else *ft = PETSC_VTK_CELL_FIELD; 249 } else { 250 if (field >= 0) { 251 const char *fieldname; 252 253 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 254 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 255 } else { 256 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n")); 257 } 258 } 259 PetscFunctionReturn(PETSC_SUCCESS); 260 } 261 262 /*@ 263 DMPlexVecView1D - Plot many 1D solutions on the same line graph 264 265 Collective 266 267 Input Parameters: 268 + dm - The `DMPLEX` object 269 . n - The number of vectors 270 . u - The array of local vectors 271 - viewer - The `PetscViewer` 272 273 Level: advanced 274 275 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 276 @*/ 277 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 278 { 279 DM cdm; 280 PetscDS ds; 281 PetscDraw draw = NULL; 282 PetscDrawLG lg; 283 Vec coordinates; 284 const PetscScalar *coords, **sol; 285 PetscReal *vals; 286 PetscInt *Nc; 287 PetscInt Nf, Nl, vStart, vEnd, eStart, eEnd; 288 char **names; 289 290 PetscFunctionBegin; 291 PetscCall(DMGetCoordinateDM(dm, &cdm)); 292 PetscCall(DMGetDS(dm, &ds)); 293 PetscCall(PetscDSGetNumFields(ds, &Nf)); 294 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 295 PetscCall(PetscDSGetComponents(ds, &Nc)); 296 297 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 298 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 299 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 300 301 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 302 for (PetscInt i = 0, l = 0; i < n; ++i) { 303 const char *vname; 304 305 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 306 for (PetscInt f = 0; f < Nf; ++f) { 307 PetscObject disc; 308 const char *fname; 309 char tmpname[PETSC_MAX_PATH_LEN]; 310 311 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 312 /* TODO Create names for components */ 313 for (PetscInt c = 0; c < Nc[f]; ++c, ++l) { 314 PetscCall(PetscObjectGetName(disc, &fname)); 315 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 316 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 317 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 318 PetscCall(PetscStrallocpy(tmpname, &names[l])); 319 } 320 } 321 } 322 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 323 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 324 PetscCall(VecGetArrayRead(coordinates, &coords)); 325 for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 326 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 327 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 328 PetscSection s; 329 PetscInt cdof, vdof; 330 331 PetscCall(DMGetLocalSection(dm, &s)); 332 PetscCall(PetscSectionGetDof(s, eStart, &cdof)); 333 PetscCall(PetscSectionGetDof(s, vStart, &vdof)); 334 if (cdof) { 335 if (vdof) { 336 // P_2 337 PetscInt vFirst = -1; 338 339 for (PetscInt e = eStart; e < eEnd; ++e) { 340 PetscScalar *xa, *xb, *svals; 341 const PetscInt *cone; 342 343 PetscCall(DMPlexGetCone(dm, e, &cone)); 344 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 345 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 346 if (e == eStart) vFirst = cone[0]; 347 for (PetscInt i = 0; i < n; ++i) { 348 PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals)); 349 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 350 } 351 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals)); 352 if (e == eEnd - 1 && cone[1] != vFirst) { 353 for (PetscInt i = 0; i < n; ++i) { 354 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 355 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 356 } 357 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 358 for (PetscInt i = 0; i < n; ++i) { 359 PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals)); 360 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 361 } 362 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals)); 363 } 364 } 365 } else { 366 // P_0 367 for (PetscInt e = eStart; e < eEnd; ++e) { 368 PetscScalar *xa, *xb, *svals; 369 const PetscInt *cone; 370 371 PetscCall(DMPlexGetCone(dm, e, &cone)); 372 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 373 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 374 for (PetscInt i = 0; i < n; ++i) { 375 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 376 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 377 } 378 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 379 } 380 } 381 } else if (vdof) { 382 // P_1 383 for (PetscInt v = vStart; v < vEnd; ++v) { 384 PetscScalar *x, *svals; 385 386 PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x)); 387 for (PetscInt i = 0; i < n; ++i) { 388 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 389 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 390 } 391 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 392 } 393 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Discretization not supported"); 394 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 395 for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 396 for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 397 PetscCall(PetscFree3(sol, names, vals)); 398 399 PetscCall(PetscDrawLGDraw(lg)); 400 PetscCall(PetscDrawLGDestroy(&lg)); 401 PetscFunctionReturn(PETSC_SUCCESS); 402 } 403 404 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 405 { 406 DM dm; 407 408 PetscFunctionBegin; 409 PetscCall(VecGetDM(u, &dm)); 410 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 411 PetscFunctionReturn(PETSC_SUCCESS); 412 } 413 414 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 415 { 416 DM dm; 417 PetscSection s; 418 PetscDraw draw, popup; 419 DM cdm; 420 PetscSection coordSection; 421 Vec coordinates; 422 const PetscScalar *array; 423 PetscReal lbound[3], ubound[3]; 424 PetscReal vbound[2], time; 425 PetscBool flg; 426 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 427 const char *name; 428 char title[PETSC_MAX_PATH_LEN]; 429 430 PetscFunctionBegin; 431 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 432 PetscCall(VecGetDM(v, &dm)); 433 PetscCall(DMGetCoordinateDim(dm, &dim)); 434 PetscCall(DMGetLocalSection(dm, &s)); 435 PetscCall(PetscSectionGetNumFields(s, &Nf)); 436 PetscCall(DMGetCoarsenLevel(dm, &level)); 437 PetscCall(DMGetCoordinateDM(dm, &cdm)); 438 PetscCall(DMGetLocalSection(cdm, &coordSection)); 439 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 440 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 441 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 442 443 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 444 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 445 446 PetscCall(VecGetLocalSize(coordinates, &N)); 447 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 448 PetscCall(PetscDrawClear(draw)); 449 450 /* Could implement something like DMDASelectFields() */ 451 for (f = 0; f < Nf; ++f) { 452 DM fdm = dm; 453 Vec fv = v; 454 IS fis; 455 char prefix[PETSC_MAX_PATH_LEN]; 456 const char *fname; 457 458 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 459 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 460 461 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 462 else prefix[0] = '\0'; 463 if (Nf > 1) { 464 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 465 PetscCall(VecGetSubVector(v, fis, &fv)); 466 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 467 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 468 } 469 for (comp = 0; comp < Nc; ++comp, ++w) { 470 PetscInt nmax = 2; 471 472 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 473 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 474 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 475 PetscCall(PetscDrawSetTitle(draw, title)); 476 477 /* TODO Get max and min only for this component */ 478 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 479 if (!flg) { 480 PetscCall(VecMin(fv, NULL, &vbound[0])); 481 PetscCall(VecMax(fv, NULL, &vbound[1])); 482 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 483 } 484 485 PetscCall(PetscDrawGetPopup(draw, &popup)); 486 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 487 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 488 PetscCall(VecGetArrayRead(fv, &array)); 489 for (c = cStart; c < cEnd; ++c) { 490 DMPolytopeType ct; 491 PetscScalar *coords = NULL, *a = NULL; 492 const PetscScalar *coords_arr; 493 PetscBool isDG; 494 PetscInt numCoords; 495 int color[4] = {-1, -1, -1, -1}; 496 497 PetscCall(DMPlexGetCellType(dm, c, &ct)); 498 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 499 if (a) { 500 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 501 color[1] = color[2] = color[3] = color[0]; 502 } else { 503 PetscScalar *vals = NULL; 504 PetscInt numVals, va; 505 506 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 507 if (!numVals) { 508 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 509 continue; 510 } 511 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 512 switch (numVals / Nc) { 513 case 1: /* P1 Clamped Segment Prism */ 514 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 515 PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]); 516 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 517 break; 518 case 3: /* P1 Triangle */ 519 case 4: /* P1 Quadrangle */ 520 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 521 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 522 break; 523 case 6: /* P2 Triangle */ 524 case 8: /* P2 Quadrangle */ 525 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 526 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 527 break; 528 default: 529 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 530 } 531 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 532 } 533 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 534 switch (numCoords) { 535 case 6: 536 case 12: /* Localized triangle */ 537 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 538 break; 539 case 8: 540 case 16: /* Localized quadrilateral */ 541 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 542 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 543 } else { 544 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 545 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 546 } 547 break; 548 default: 549 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 550 } 551 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 552 } 553 PetscCall(VecRestoreArrayRead(fv, &array)); 554 PetscCall(PetscDrawFlush(draw)); 555 PetscCall(PetscDrawPause(draw)); 556 PetscCall(PetscDrawSave(draw)); 557 } 558 if (Nf > 1) { 559 PetscCall(VecRestoreSubVector(v, fis, &fv)); 560 PetscCall(ISDestroy(&fis)); 561 PetscCall(DMDestroy(&fdm)); 562 } 563 } 564 PetscFunctionReturn(PETSC_SUCCESS); 565 } 566 567 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 568 { 569 DM dm; 570 PetscDraw draw; 571 PetscInt dim; 572 PetscBool isnull; 573 574 PetscFunctionBegin; 575 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 576 PetscCall(PetscDrawIsNull(draw, &isnull)); 577 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 578 579 PetscCall(VecGetDM(v, &dm)); 580 PetscCall(DMGetCoordinateDim(dm, &dim)); 581 switch (dim) { 582 case 1: 583 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 584 break; 585 case 2: 586 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 587 break; 588 default: 589 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 590 } 591 PetscFunctionReturn(PETSC_SUCCESS); 592 } 593 594 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 595 { 596 DM dm; 597 Vec locv; 598 const char *name; 599 PetscSection section; 600 PetscInt pStart, pEnd; 601 PetscInt numFields; 602 PetscViewerVTKFieldType ft; 603 604 PetscFunctionBegin; 605 PetscCall(VecGetDM(v, &dm)); 606 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 607 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 608 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 609 PetscCall(VecCopy(v, locv)); 610 PetscCall(DMGetLocalSection(dm, §ion)); 611 PetscCall(PetscSectionGetNumFields(section, &numFields)); 612 if (!numFields) { 613 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 614 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 615 } else { 616 PetscInt f; 617 618 for (f = 0; f < numFields; f++) { 619 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 620 if (ft == PETSC_VTK_INVALID) continue; 621 PetscCall(PetscObjectReference((PetscObject)locv)); 622 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 623 } 624 PetscCall(VecDestroy(&locv)); 625 } 626 PetscFunctionReturn(PETSC_SUCCESS); 627 } 628 629 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 630 { 631 DM dm; 632 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython; 633 634 PetscFunctionBegin; 635 PetscCall(VecGetDM(v, &dm)); 636 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 640 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 641 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 642 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 643 if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) { 644 PetscInt i, numFields; 645 PetscObject fe; 646 PetscBool fem = PETSC_FALSE; 647 Vec locv = v; 648 const char *name; 649 PetscInt step; 650 PetscReal time; 651 652 PetscCall(DMGetNumFields(dm, &numFields)); 653 for (i = 0; i < numFields; i++) { 654 PetscCall(DMGetField(dm, i, NULL, &fe)); 655 if (fe->classid == PETSCFE_CLASSID) { 656 fem = PETSC_TRUE; 657 break; 658 } 659 } 660 if (fem) { 661 PetscObject isZero; 662 663 PetscCall(DMGetLocalVector(dm, &locv)); 664 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 665 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 666 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 667 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 668 PetscCall(VecCopy(v, locv)); 669 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 670 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 671 } 672 if (isvtk) { 673 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 674 } else if (ishdf5) { 675 #if defined(PETSC_HAVE_HDF5) 676 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 677 #else 678 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 679 #endif 680 } else if (isdraw) { 681 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 682 } else if (ispython) { 683 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv)); 684 } else if (isglvis) { 685 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 686 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 687 PetscCall(VecView_GLVis(locv, viewer)); 688 } else if (iscgns) { 689 #if defined(PETSC_HAVE_CGNS) 690 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 691 #else 692 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 693 #endif 694 } 695 if (fem) { 696 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 697 PetscCall(DMRestoreLocalVector(dm, &locv)); 698 } 699 } else { 700 PetscBool isseq; 701 702 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 703 if (isseq) PetscCall(VecView_Seq(v, viewer)); 704 else PetscCall(VecView_MPI(v, viewer)); 705 } 706 PetscFunctionReturn(PETSC_SUCCESS); 707 } 708 709 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 710 { 711 DM dm; 712 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython; 713 714 PetscFunctionBegin; 715 PetscCall(VecGetDM(v, &dm)); 716 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 721 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 722 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 723 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 724 if (isvtk || isdraw || isglvis || iscgns || ispython) { 725 Vec locv; 726 PetscObject isZero; 727 const char *name; 728 729 PetscCall(DMGetLocalVector(dm, &locv)); 730 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 731 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 732 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 733 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 734 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 735 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 736 PetscCall(VecView_Plex_Local(locv, viewer)); 737 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 738 PetscCall(DMRestoreLocalVector(dm, &locv)); 739 } else if (ishdf5) { 740 #if defined(PETSC_HAVE_HDF5) 741 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 742 #else 743 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 744 #endif 745 } else if (isexodusii) { 746 #if defined(PETSC_HAVE_EXODUSII) 747 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 748 #else 749 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 750 #endif 751 } else { 752 PetscBool isseq; 753 754 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 755 if (isseq) PetscCall(VecView_Seq(v, viewer)); 756 else PetscCall(VecView_MPI(v, viewer)); 757 } 758 PetscFunctionReturn(PETSC_SUCCESS); 759 } 760 761 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 762 { 763 DM dm; 764 MPI_Comm comm; 765 PetscViewerFormat format; 766 Vec v; 767 PetscBool isvtk, ishdf5; 768 769 PetscFunctionBegin; 770 PetscCall(VecGetDM(originalv, &dm)); 771 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 772 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 773 PetscCall(PetscViewerGetFormat(viewer, &format)); 774 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 775 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 776 if (format == PETSC_VIEWER_NATIVE) { 777 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 778 /* this need a better fix */ 779 if (dm->useNatural) { 780 if (dm->sfNatural) { 781 const char *vecname; 782 PetscInt n, nroots; 783 784 PetscCall(VecGetLocalSize(originalv, &n)); 785 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 786 if (n == nroots) { 787 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 788 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 789 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 790 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 791 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 792 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 793 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 794 } else v = originalv; 795 } else v = originalv; 796 797 if (ishdf5) { 798 #if defined(PETSC_HAVE_HDF5) 799 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 800 #else 801 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 802 #endif 803 } else if (isvtk) { 804 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 805 } else { 806 PetscBool isseq; 807 808 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 809 if (isseq) PetscCall(VecView_Seq(v, viewer)); 810 else PetscCall(VecView_MPI(v, viewer)); 811 } 812 if (v != originalv) PetscCall(VecDestroy(&v)); 813 PetscFunctionReturn(PETSC_SUCCESS); 814 } 815 816 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 817 { 818 DM dm; 819 PetscBool ishdf5; 820 821 PetscFunctionBegin; 822 PetscCall(VecGetDM(v, &dm)); 823 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 824 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 825 if (ishdf5) { 826 DM dmBC; 827 Vec gv; 828 const char *name; 829 830 PetscCall(DMGetOutputDM(dm, &dmBC)); 831 PetscCall(DMGetGlobalVector(dmBC, &gv)); 832 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 833 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 834 PetscCall(VecLoad_Default(gv, viewer)); 835 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 836 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 837 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 838 } else PetscCall(VecLoad_Default(v, viewer)); 839 PetscFunctionReturn(PETSC_SUCCESS); 840 } 841 842 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 843 { 844 DM dm; 845 PetscBool ishdf5, isexodusii, iscgns; 846 847 PetscFunctionBegin; 848 PetscCall(VecGetDM(v, &dm)); 849 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 850 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 851 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 852 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 853 if (ishdf5) { 854 #if defined(PETSC_HAVE_HDF5) 855 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 856 #else 857 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 858 #endif 859 } else if (isexodusii) { 860 #if defined(PETSC_HAVE_EXODUSII) 861 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 862 #else 863 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 864 #endif 865 } else if (iscgns) { 866 #if defined(PETSC_HAVE_CGNS) 867 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 868 #else 869 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 870 #endif 871 } else PetscCall(VecLoad_Default(v, viewer)); 872 PetscFunctionReturn(PETSC_SUCCESS); 873 } 874 875 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 876 { 877 DM dm; 878 PetscViewerFormat format; 879 PetscBool ishdf5; 880 881 PetscFunctionBegin; 882 PetscCall(VecGetDM(originalv, &dm)); 883 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 884 PetscCall(PetscViewerGetFormat(viewer, &format)); 885 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 886 if (format == PETSC_VIEWER_NATIVE) { 887 if (dm->useNatural) { 888 if (dm->sfNatural) { 889 if (ishdf5) { 890 #if defined(PETSC_HAVE_HDF5) 891 Vec v; 892 const char *vecname; 893 894 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 895 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 896 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 897 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 898 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 899 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 900 PetscCall(VecDestroy(&v)); 901 #else 902 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 903 #endif 904 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 905 } 906 } else PetscCall(VecLoad_Default(originalv, viewer)); 907 } 908 PetscFunctionReturn(PETSC_SUCCESS); 909 } 910 911 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 912 { 913 PetscSection coordSection; 914 Vec coordinates; 915 DMLabel depthLabel, celltypeLabel; 916 const char *name[4]; 917 const PetscScalar *a; 918 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 919 920 PetscFunctionBegin; 921 PetscCall(DMGetDimension(dm, &dim)); 922 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 923 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 924 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 925 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 926 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 927 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 928 PetscCall(VecGetArrayRead(coordinates, &a)); 929 name[0] = "vertex"; 930 name[1] = "edge"; 931 name[dim - 1] = "face"; 932 name[dim] = "cell"; 933 for (c = cStart; c < cEnd; ++c) { 934 PetscInt *closure = NULL; 935 PetscInt closureSize, cl, ct; 936 937 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 938 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 939 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 940 PetscCall(PetscViewerASCIIPushTab(viewer)); 941 for (cl = 0; cl < closureSize * 2; cl += 2) { 942 PetscInt point = closure[cl], depth, dof, off, d, p; 943 944 if ((point < pStart) || (point >= pEnd)) continue; 945 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 946 if (!dof) continue; 947 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 948 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 949 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 950 for (p = 0; p < dof / dim; ++p) { 951 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 952 for (d = 0; d < dim; ++d) { 953 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 955 } 956 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 957 } 958 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 959 } 960 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 961 PetscCall(PetscViewerASCIIPopTab(viewer)); 962 } 963 PetscCall(VecRestoreArrayRead(coordinates, &a)); 964 PetscFunctionReturn(PETSC_SUCCESS); 965 } 966 967 typedef enum { 968 CS_CARTESIAN, 969 CS_POLAR, 970 CS_CYLINDRICAL, 971 CS_SPHERICAL 972 } CoordSystem; 973 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 974 975 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 976 { 977 PetscInt i; 978 979 PetscFunctionBegin; 980 if (dim > 3) { 981 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 982 } else { 983 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 984 985 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 986 switch (cs) { 987 case CS_CARTESIAN: 988 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 989 break; 990 case CS_POLAR: 991 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 992 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 993 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 994 break; 995 case CS_CYLINDRICAL: 996 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 997 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 998 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 999 trcoords[2] = coords[2]; 1000 break; 1001 case CS_SPHERICAL: 1002 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 1003 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 1004 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 1005 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 1006 break; 1007 } 1008 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 1009 } 1010 PetscFunctionReturn(PETSC_SUCCESS); 1011 } 1012 1013 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 1014 { 1015 DM_Plex *mesh = (DM_Plex *)dm->data; 1016 DM cdm, cdmCell; 1017 PetscSection coordSection, coordSectionCell; 1018 Vec coordinates, coordinatesCell; 1019 PetscViewerFormat format; 1020 1021 PetscFunctionBegin; 1022 PetscCall(PetscViewerGetFormat(viewer, &format)); 1023 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1024 const char *name; 1025 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1026 PetscInt pStart, pEnd, p, numLabels, l; 1027 PetscMPIInt rank, size; 1028 1029 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1030 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1031 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1032 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1033 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1034 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1035 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1036 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1037 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1038 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1039 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1040 PetscCall(DMGetDimension(dm, &dim)); 1041 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1042 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1043 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1044 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1045 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1046 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1047 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1048 for (p = pStart; p < pEnd; ++p) { 1049 PetscInt dof, off, s; 1050 1051 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1052 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1053 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1054 } 1055 PetscCall(PetscViewerFlush(viewer)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1057 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1058 for (p = pStart; p < pEnd; ++p) { 1059 PetscInt dof, off, c; 1060 1061 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1062 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1063 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 1064 } 1065 PetscCall(PetscViewerFlush(viewer)); 1066 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1067 if (coordSection && coordinates) { 1068 CoordSystem cs = CS_CARTESIAN; 1069 const PetscScalar *array, *arrayCell = NULL; 1070 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1071 PetscMPIInt rank; 1072 const char *name; 1073 1074 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1075 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1076 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1077 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1078 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1079 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1080 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1081 pStart = PetscMin(pvStart, pcStart); 1082 pEnd = PetscMax(pvEnd, pcEnd); 1083 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1084 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1085 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1086 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1087 1088 PetscCall(VecGetArrayRead(coordinates, &array)); 1089 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1090 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1091 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1092 for (p = pStart; p < pEnd; ++p) { 1093 PetscInt dof, off; 1094 1095 if (p >= pvStart && p < pvEnd) { 1096 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1097 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1098 if (dof) { 1099 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1100 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1101 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1102 } 1103 } 1104 if (cdmCell && p >= pcStart && p < pcEnd) { 1105 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1106 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1107 if (dof) { 1108 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1109 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1110 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1111 } 1112 } 1113 } 1114 PetscCall(PetscViewerFlush(viewer)); 1115 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1116 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1117 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1118 } 1119 PetscCall(DMGetNumLabels(dm, &numLabels)); 1120 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1121 for (l = 0; l < numLabels; ++l) { 1122 DMLabel label; 1123 PetscBool isdepth; 1124 const char *name; 1125 1126 PetscCall(DMGetLabelName(dm, l, &name)); 1127 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1128 if (isdepth) continue; 1129 PetscCall(DMGetLabel(dm, name, &label)); 1130 PetscCall(DMLabelView(label, viewer)); 1131 } 1132 if (size > 1) { 1133 PetscSF sf; 1134 1135 PetscCall(DMGetPointSF(dm, &sf)); 1136 PetscCall(PetscSFView(sf, viewer)); 1137 } 1138 if (mesh->periodic.face_sfs) 1139 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1140 PetscCall(PetscViewerFlush(viewer)); 1141 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1142 const char *name, *color; 1143 const char *defcolors[3] = {"gray", "orange", "green"}; 1144 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1145 char lname[PETSC_MAX_PATH_LEN]; 1146 PetscReal scale = 2.0; 1147 PetscReal tikzscale = 1.0; 1148 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1149 double tcoords[3]; 1150 PetscScalar *coords; 1151 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 1152 PetscMPIInt rank, size; 1153 char **names, **colors, **lcolors; 1154 PetscBool flg, lflg; 1155 PetscBT wp = NULL; 1156 PetscInt pEnd, pStart; 1157 1158 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1159 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1160 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1161 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1162 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1163 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1164 PetscCall(DMGetDimension(dm, &dim)); 1165 PetscCall(DMPlexGetDepth(dm, &depth)); 1166 PetscCall(DMGetNumLabels(dm, &numLabels)); 1167 numLabels = PetscMax(numLabels, 10); 1168 numColors = 10; 1169 numLColors = 10; 1170 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1171 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1172 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1173 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1174 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1175 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1176 n = 4; 1177 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1178 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1179 n = 4; 1180 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1181 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1182 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1183 if (!useLabels) numLabels = 0; 1184 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1185 if (!useColors) { 1186 numColors = 3; 1187 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1188 } 1189 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1190 if (!useColors) { 1191 numLColors = 4; 1192 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1193 } 1194 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1195 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1196 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1197 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1198 if (depth < dim) plotEdges = PETSC_FALSE; 1199 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1200 1201 /* filter points with labelvalue != labeldefaultvalue */ 1202 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1203 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1204 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1205 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1206 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1207 if (lflg) { 1208 DMLabel lbl; 1209 1210 PetscCall(DMGetLabel(dm, lname, &lbl)); 1211 if (lbl) { 1212 PetscInt val, defval; 1213 1214 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1215 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1216 for (c = pStart; c < pEnd; c++) { 1217 PetscInt *closure = NULL; 1218 PetscInt closureSize; 1219 1220 PetscCall(DMLabelGetValue(lbl, c, &val)); 1221 if (val == defval) continue; 1222 1223 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1224 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1225 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1226 } 1227 } 1228 } 1229 1230 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1231 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1232 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1234 \\documentclass[tikz]{standalone}\n\n\ 1235 \\usepackage{pgflibraryshapes}\n\ 1236 \\usetikzlibrary{backgrounds}\n\ 1237 \\usetikzlibrary{arrows}\n\ 1238 \\begin{document}\n")); 1239 if (size > 1) { 1240 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1241 for (p = 0; p < size; ++p) { 1242 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1243 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1244 } 1245 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1246 } 1247 if (drawHasse) { 1248 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1249 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1258 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1264 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1265 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1266 } 1267 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1268 1269 /* Plot vertices */ 1270 PetscCall(VecGetArray(coordinates, &coords)); 1271 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1272 for (v = vStart; v < vEnd; ++v) { 1273 PetscInt off, dof, d; 1274 PetscBool isLabeled = PETSC_FALSE; 1275 1276 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1277 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1278 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1280 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1281 for (d = 0; d < dof; ++d) { 1282 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1283 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1284 } 1285 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1286 if (dim == 3) { 1287 PetscReal tmp = tcoords[1]; 1288 tcoords[1] = tcoords[2]; 1289 tcoords[2] = -tmp; 1290 } 1291 for (d = 0; d < dof; ++d) { 1292 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1293 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1294 } 1295 if (drawHasse) color = colors[0 % numColors]; 1296 else color = colors[rank % numColors]; 1297 for (l = 0; l < numLabels; ++l) { 1298 PetscInt val; 1299 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1300 if (val >= 0) { 1301 color = lcolors[l % numLColors]; 1302 isLabeled = PETSC_TRUE; 1303 break; 1304 } 1305 } 1306 if (drawNumbers[0]) { 1307 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1308 } else if (drawColors[0]) { 1309 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1310 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1311 } 1312 PetscCall(VecRestoreArray(coordinates, &coords)); 1313 PetscCall(PetscViewerFlush(viewer)); 1314 /* Plot edges */ 1315 if (plotEdges) { 1316 PetscCall(VecGetArray(coordinates, &coords)); 1317 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1318 for (e = eStart; e < eEnd; ++e) { 1319 const PetscInt *cone; 1320 PetscInt coneSize, offA, offB, dof, d; 1321 1322 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1323 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1324 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1325 PetscCall(DMPlexGetCone(dm, e, &cone)); 1326 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1327 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1328 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1329 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1330 for (d = 0; d < dof; ++d) { 1331 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1332 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1333 } 1334 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1335 if (dim == 3) { 1336 PetscReal tmp = tcoords[1]; 1337 tcoords[1] = tcoords[2]; 1338 tcoords[2] = -tmp; 1339 } 1340 for (d = 0; d < dof; ++d) { 1341 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1342 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1343 } 1344 if (drawHasse) color = colors[1 % numColors]; 1345 else color = colors[rank % numColors]; 1346 for (l = 0; l < numLabels; ++l) { 1347 PetscInt val; 1348 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1349 if (val >= 0) { 1350 color = lcolors[l % numLColors]; 1351 break; 1352 } 1353 } 1354 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1355 } 1356 PetscCall(VecRestoreArray(coordinates, &coords)); 1357 PetscCall(PetscViewerFlush(viewer)); 1358 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1359 } 1360 /* Plot cells */ 1361 if (dim == 3 || !drawNumbers[1]) { 1362 for (e = eStart; e < eEnd; ++e) { 1363 const PetscInt *cone; 1364 1365 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1366 color = colors[rank % numColors]; 1367 for (l = 0; l < numLabels; ++l) { 1368 PetscInt val; 1369 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1370 if (val >= 0) { 1371 color = lcolors[l % numLColors]; 1372 break; 1373 } 1374 } 1375 PetscCall(DMPlexGetCone(dm, e, &cone)); 1376 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1377 } 1378 } else { 1379 DMPolytopeType ct; 1380 1381 /* Drawing a 2D polygon */ 1382 for (c = cStart; c < cEnd; ++c) { 1383 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1384 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1385 if (DMPolytopeTypeIsHybrid(ct)) { 1386 const PetscInt *cone; 1387 PetscInt coneSize, e; 1388 1389 PetscCall(DMPlexGetCone(dm, c, &cone)); 1390 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1391 for (e = 0; e < coneSize; ++e) { 1392 const PetscInt *econe; 1393 1394 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1395 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1396 } 1397 } else { 1398 PetscInt *closure = NULL; 1399 PetscInt closureSize, Nv = 0, v; 1400 1401 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1402 for (p = 0; p < closureSize * 2; p += 2) { 1403 const PetscInt point = closure[p]; 1404 1405 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1406 } 1407 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1408 for (v = 0; v <= Nv; ++v) { 1409 const PetscInt vertex = closure[v % Nv]; 1410 1411 if (v > 0) { 1412 if (plotEdges) { 1413 const PetscInt *edge; 1414 PetscInt endpoints[2], ne; 1415 1416 endpoints[0] = closure[v - 1]; 1417 endpoints[1] = vertex; 1418 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1419 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1420 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1421 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1422 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1423 } 1424 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1425 } 1426 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1427 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1428 } 1429 } 1430 } 1431 for (c = cStart; c < cEnd; ++c) { 1432 double ccoords[3] = {0.0, 0.0, 0.0}; 1433 PetscBool isLabeled = PETSC_FALSE; 1434 PetscScalar *cellCoords = NULL; 1435 const PetscScalar *array; 1436 PetscInt numCoords, cdim, d; 1437 PetscBool isDG; 1438 1439 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1440 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1441 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1442 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1443 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1444 for (p = 0; p < numCoords / cdim; ++p) { 1445 for (d = 0; d < cdim; ++d) { 1446 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1447 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1448 } 1449 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1450 if (cdim == 3) { 1451 PetscReal tmp = tcoords[1]; 1452 tcoords[1] = tcoords[2]; 1453 tcoords[2] = -tmp; 1454 } 1455 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1456 } 1457 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1458 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1459 for (d = 0; d < cdim; ++d) { 1460 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1461 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1462 } 1463 if (drawHasse) color = colors[depth % numColors]; 1464 else color = colors[rank % numColors]; 1465 for (l = 0; l < numLabels; ++l) { 1466 PetscInt val; 1467 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1468 if (val >= 0) { 1469 color = lcolors[l % numLColors]; 1470 isLabeled = PETSC_TRUE; 1471 break; 1472 } 1473 } 1474 if (drawNumbers[dim]) { 1475 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1476 } else if (drawColors[dim]) { 1477 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1478 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1479 } 1480 if (drawHasse) { 1481 int height = 0; 1482 1483 color = colors[depth % numColors]; 1484 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1485 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1486 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1487 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1489 1490 if (depth > 2) { 1491 color = colors[1 % numColors]; 1492 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1493 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1494 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1495 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1496 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1497 } 1498 1499 color = colors[1 % numColors]; 1500 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1502 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1503 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1504 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1505 1506 color = colors[0 % numColors]; 1507 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1510 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1511 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1512 1513 for (p = pStart; p < pEnd; ++p) { 1514 const PetscInt *cone; 1515 PetscInt coneSize, cp; 1516 1517 PetscCall(DMPlexGetCone(dm, p, &cone)); 1518 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1519 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1520 } 1521 } 1522 PetscCall(PetscViewerFlush(viewer)); 1523 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1524 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1525 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1526 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1527 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1528 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1529 PetscCall(PetscFree3(names, colors, lcolors)); 1530 PetscCall(PetscBTDestroy(&wp)); 1531 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1532 Vec cown, acown; 1533 VecScatter sct; 1534 ISLocalToGlobalMapping g2l; 1535 IS gid, acis; 1536 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1537 MPI_Group ggroup, ngroup; 1538 PetscScalar *array, nid; 1539 const PetscInt *idxs; 1540 PetscInt *idxs2, *start, *adjacency, *work; 1541 PetscInt64 lm[3], gm[3]; 1542 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1543 PetscMPIInt d1, d2, rank; 1544 1545 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1546 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1547 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1548 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1549 #endif 1550 if (ncomm != MPI_COMM_NULL) { 1551 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1552 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1553 d1 = 0; 1554 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1555 nid = d2; 1556 PetscCallMPI(MPI_Group_free(&ggroup)); 1557 PetscCallMPI(MPI_Group_free(&ngroup)); 1558 PetscCallMPI(MPI_Comm_free(&ncomm)); 1559 } else nid = 0.0; 1560 1561 /* Get connectivity */ 1562 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1563 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1564 1565 /* filter overlapped local cells */ 1566 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1567 PetscCall(ISGetIndices(gid, &idxs)); 1568 PetscCall(ISGetLocalSize(gid, &cum)); 1569 PetscCall(PetscMalloc1(cum, &idxs2)); 1570 for (c = cStart, cum = 0; c < cEnd; c++) { 1571 if (idxs[c - cStart] < 0) continue; 1572 idxs2[cum++] = idxs[c - cStart]; 1573 } 1574 PetscCall(ISRestoreIndices(gid, &idxs)); 1575 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1576 PetscCall(ISDestroy(&gid)); 1577 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1578 1579 /* support for node-aware cell locality */ 1580 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1581 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1582 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1583 PetscCall(VecGetArray(cown, &array)); 1584 for (c = 0; c < numVertices; c++) array[c] = nid; 1585 PetscCall(VecRestoreArray(cown, &array)); 1586 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1587 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1588 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1589 PetscCall(ISDestroy(&acis)); 1590 PetscCall(VecScatterDestroy(&sct)); 1591 PetscCall(VecDestroy(&cown)); 1592 1593 /* compute edgeCut */ 1594 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1595 PetscCall(PetscMalloc1(cum, &work)); 1596 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1597 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1598 PetscCall(ISDestroy(&gid)); 1599 PetscCall(VecGetArray(acown, &array)); 1600 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1601 PetscInt totl; 1602 1603 totl = start[c + 1] - start[c]; 1604 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1605 for (i = 0; i < totl; i++) { 1606 if (work[i] < 0) { 1607 ect += 1; 1608 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1609 } 1610 } 1611 } 1612 PetscCall(PetscFree(work)); 1613 PetscCall(VecRestoreArray(acown, &array)); 1614 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1615 lm[1] = -numVertices; 1616 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1617 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1618 lm[0] = ect; /* edgeCut */ 1619 lm[1] = ectn; /* node-aware edgeCut */ 1620 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1621 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1622 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1623 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1624 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1625 #else 1626 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1627 #endif 1628 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1629 PetscCall(PetscFree(start)); 1630 PetscCall(PetscFree(adjacency)); 1631 PetscCall(VecDestroy(&acown)); 1632 } else { 1633 const char *name; 1634 PetscInt *sizes, *hybsizes, *ghostsizes; 1635 PetscInt locDepth, depth, cellHeight, dim, d; 1636 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1637 PetscInt numLabels, l, maxSize = 17; 1638 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1639 MPI_Comm comm; 1640 PetscMPIInt size, rank; 1641 1642 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1643 PetscCallMPI(MPI_Comm_size(comm, &size)); 1644 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1645 PetscCall(DMGetDimension(dm, &dim)); 1646 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1647 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1648 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1649 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1650 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1651 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1652 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1653 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1654 gcNum = gcEnd - gcStart; 1655 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1656 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1657 for (d = 0; d <= depth; d++) { 1658 PetscInt Nc[2] = {0, 0}, ict; 1659 1660 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1661 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1662 ict = ct0; 1663 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1664 ct0 = (DMPolytopeType)ict; 1665 for (p = pStart; p < pEnd; ++p) { 1666 DMPolytopeType ct; 1667 1668 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1669 if (ct == ct0) ++Nc[0]; 1670 else ++Nc[1]; 1671 } 1672 if (size < maxSize) { 1673 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1674 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1675 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1676 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1677 for (p = 0; p < size; ++p) { 1678 if (rank == 0) { 1679 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1680 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1681 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1682 } 1683 } 1684 } else { 1685 PetscInt locMinMax[2]; 1686 1687 locMinMax[0] = Nc[0] + Nc[1]; 1688 locMinMax[1] = Nc[0] + Nc[1]; 1689 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1690 locMinMax[0] = Nc[1]; 1691 locMinMax[1] = Nc[1]; 1692 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1693 if (d == depth) { 1694 locMinMax[0] = gcNum; 1695 locMinMax[1] = gcNum; 1696 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1697 } 1698 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1699 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1700 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1701 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1702 } 1703 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1704 } 1705 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1706 { 1707 const PetscReal *maxCell; 1708 const PetscReal *L; 1709 PetscBool localized; 1710 1711 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1712 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1713 if (L || localized) { 1714 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1715 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1716 if (L) { 1717 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1718 for (d = 0; d < dim; ++d) { 1719 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1720 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1721 } 1722 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1723 } 1724 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1725 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1726 } 1727 } 1728 PetscCall(DMGetNumLabels(dm, &numLabels)); 1729 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1730 for (l = 0; l < numLabels; ++l) { 1731 DMLabel label; 1732 const char *name; 1733 PetscInt *values; 1734 PetscInt numValues, v; 1735 1736 PetscCall(DMGetLabelName(dm, l, &name)); 1737 PetscCall(DMGetLabel(dm, name, &label)); 1738 PetscCall(DMLabelGetNumValues(label, &numValues)); 1739 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1740 1741 { // Extract array of DMLabel values so it can be sorted 1742 IS is_values; 1743 const PetscInt *is_values_local = NULL; 1744 1745 PetscCall(DMLabelGetValueIS(label, &is_values)); 1746 PetscCall(ISGetIndices(is_values, &is_values_local)); 1747 PetscCall(PetscMalloc1(numValues, &values)); 1748 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1749 PetscCall(PetscSortInt(numValues, values)); 1750 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1751 PetscCall(ISDestroy(&is_values)); 1752 } 1753 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1754 for (v = 0; v < numValues; ++v) { 1755 PetscInt size; 1756 1757 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1758 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1759 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1760 } 1761 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1762 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1763 PetscCall(PetscFree(values)); 1764 } 1765 { 1766 char **labelNames; 1767 PetscInt Nl = numLabels; 1768 PetscBool flg; 1769 1770 PetscCall(PetscMalloc1(Nl, &labelNames)); 1771 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1772 for (l = 0; l < Nl; ++l) { 1773 DMLabel label; 1774 1775 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1776 if (flg) { 1777 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1778 PetscCall(DMLabelView(label, viewer)); 1779 } 1780 PetscCall(PetscFree(labelNames[l])); 1781 } 1782 PetscCall(PetscFree(labelNames)); 1783 } 1784 /* If no fields are specified, people do not want to see adjacency */ 1785 if (dm->Nf) { 1786 PetscInt f; 1787 1788 for (f = 0; f < dm->Nf; ++f) { 1789 const char *name; 1790 1791 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1792 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1793 PetscCall(PetscViewerASCIIPushTab(viewer)); 1794 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1795 if (dm->fields[f].adjacency[0]) { 1796 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1797 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1798 } else { 1799 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1800 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1801 } 1802 PetscCall(PetscViewerASCIIPopTab(viewer)); 1803 } 1804 } 1805 DMPlexTransform tr; 1806 1807 PetscCall(DMPlexGetTransform(dm, &tr)); 1808 if (tr) { 1809 PetscCall(PetscViewerASCIIPushTab(viewer)); 1810 PetscCall(PetscViewerASCIIPrintf(viewer, "Created using transform:\n")); 1811 PetscCall(DMPlexTransformView(tr, viewer)); 1812 PetscCall(PetscViewerASCIIPopTab(viewer)); 1813 } 1814 PetscCall(DMGetCoarseDM(dm, &cdm)); 1815 if (cdm) { 1816 PetscCall(PetscViewerASCIIPushTab(viewer)); 1817 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1818 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1819 PetscCall(PetscViewerASCIIPopTab(viewer)); 1820 } 1821 } 1822 PetscFunctionReturn(PETSC_SUCCESS); 1823 } 1824 1825 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1826 { 1827 DMPolytopeType ct; 1828 PetscMPIInt rank; 1829 PetscInt cdim; 1830 1831 PetscFunctionBegin; 1832 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1833 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1834 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1835 switch (ct) { 1836 case DM_POLYTOPE_SEGMENT: 1837 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1838 switch (cdim) { 1839 case 1: { 1840 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1841 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1842 1843 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1844 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1845 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1846 } break; 1847 case 2: { 1848 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1849 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1850 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1851 1852 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1853 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1854 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1855 } break; 1856 default: 1857 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1858 } 1859 break; 1860 case DM_POLYTOPE_TRIANGLE: 1861 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1862 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1863 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1864 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1865 break; 1866 case DM_POLYTOPE_QUADRILATERAL: 1867 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1868 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1869 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1870 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1871 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1872 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1873 break; 1874 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1875 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1876 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1877 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1878 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1879 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1880 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1881 break; 1882 case DM_POLYTOPE_FV_GHOST: 1883 break; 1884 default: 1885 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1886 } 1887 PetscFunctionReturn(PETSC_SUCCESS); 1888 } 1889 1890 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1891 { 1892 PetscReal centroid[2] = {0., 0.}; 1893 PetscMPIInt rank; 1894 PetscMPIInt fillColor; 1895 1896 PetscFunctionBegin; 1897 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1898 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1899 for (PetscInt v = 0; v < Nv; ++v) { 1900 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1901 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1902 } 1903 for (PetscInt e = 0; e < Nv; ++e) { 1904 refCoords[0] = refVertices[e * 2 + 0]; 1905 refCoords[1] = refVertices[e * 2 + 1]; 1906 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1907 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1908 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1909 } 1910 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1911 for (PetscInt d = 0; d < edgeDiv; ++d) { 1912 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1913 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1914 } 1915 } 1916 PetscFunctionReturn(PETSC_SUCCESS); 1917 } 1918 1919 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1920 { 1921 DMPolytopeType ct; 1922 1923 PetscFunctionBegin; 1924 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1925 switch (ct) { 1926 case DM_POLYTOPE_TRIANGLE: { 1927 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1928 1929 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1930 } break; 1931 case DM_POLYTOPE_QUADRILATERAL: { 1932 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1933 1934 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1935 } break; 1936 default: 1937 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1938 } 1939 PetscFunctionReturn(PETSC_SUCCESS); 1940 } 1941 1942 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1943 { 1944 PetscDraw draw; 1945 DM cdm; 1946 PetscSection coordSection; 1947 Vec coordinates; 1948 PetscReal xyl[3], xyr[3]; 1949 PetscReal *refCoords, *edgeCoords; 1950 PetscBool isnull, drawAffine; 1951 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1952 1953 PetscFunctionBegin; 1954 PetscCall(DMGetCoordinateDim(dm, &dim)); 1955 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1956 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1957 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1958 edgeDiv = cDegree + 1; 1959 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1960 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1961 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1962 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1963 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1964 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1965 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1966 1967 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1968 PetscCall(PetscDrawIsNull(draw, &isnull)); 1969 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1970 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1971 1972 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1973 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1974 PetscCall(PetscDrawClear(draw)); 1975 1976 for (c = cStart; c < cEnd; ++c) { 1977 PetscScalar *coords = NULL; 1978 const PetscScalar *coords_arr; 1979 PetscInt numCoords; 1980 PetscBool isDG; 1981 1982 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1983 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1984 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1985 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1986 } 1987 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1988 PetscCall(PetscDrawFlush(draw)); 1989 PetscCall(PetscDrawPause(draw)); 1990 PetscCall(PetscDrawSave(draw)); 1991 PetscFunctionReturn(PETSC_SUCCESS); 1992 } 1993 1994 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1995 { 1996 DM odm = dm, rdm = dm, cdm; 1997 PetscFE fe; 1998 PetscSpace sp; 1999 PetscClassId id; 2000 PetscInt degree; 2001 PetscBool hoView = PETSC_TRUE; 2002 2003 PetscFunctionBegin; 2004 PetscObjectOptionsBegin((PetscObject)dm); 2005 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 2006 PetscOptionsEnd(); 2007 PetscCall(PetscObjectReference((PetscObject)dm)); 2008 *hdm = dm; 2009 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 2010 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2011 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 2012 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 2013 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 2014 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 2015 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 2016 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 2017 DM cdm, rcdm; 2018 Mat In; 2019 Vec cl, rcl; 2020 2021 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 2022 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 2023 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 2024 PetscCall(DMGetCoordinateDM(odm, &cdm)); 2025 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 2026 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 2027 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 2028 PetscCall(DMSetCoarseDM(rcdm, cdm)); 2029 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 2030 PetscCall(MatMult(In, cl, rcl)); 2031 PetscCall(MatDestroy(&In)); 2032 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 2033 PetscCall(DMDestroy(&odm)); 2034 odm = rdm; 2035 } 2036 *hdm = rdm; 2037 PetscFunctionReturn(PETSC_SUCCESS); 2038 } 2039 2040 #if defined(PETSC_HAVE_EXODUSII) 2041 #include <exodusII.h> 2042 #include <petscviewerexodusii.h> 2043 #endif 2044 2045 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 2046 { 2047 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 2048 char name[PETSC_MAX_PATH_LEN]; 2049 2050 PetscFunctionBegin; 2051 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2052 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2053 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 2054 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2055 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2056 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2057 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 2058 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 2059 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 2060 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2061 if (iascii) { 2062 PetscViewerFormat format; 2063 PetscCall(PetscViewerGetFormat(viewer, &format)); 2064 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 2065 else PetscCall(DMPlexView_Ascii(dm, viewer)); 2066 } else if (ishdf5) { 2067 #if defined(PETSC_HAVE_HDF5) 2068 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 2069 #else 2070 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2071 #endif 2072 } else if (isvtk) { 2073 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2074 } else if (isdraw) { 2075 DM hdm; 2076 2077 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2078 PetscCall(DMPlexView_Draw(hdm, viewer)); 2079 PetscCall(DMDestroy(&hdm)); 2080 } else if (isglvis) { 2081 PetscCall(DMPlexView_GLVis(dm, viewer)); 2082 #if defined(PETSC_HAVE_EXODUSII) 2083 } else if (isexodus) { 2084 /* 2085 exodusII requires that all sets be part of exactly one cell set. 2086 If the dm does not have a "Cell Sets" label defined, we create one 2087 with ID 1, containing all cells. 2088 Note that if the Cell Sets label is defined but does not cover all cells, 2089 we may still have a problem. This should probably be checked here or in the viewer; 2090 */ 2091 PetscInt numCS; 2092 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2093 if (!numCS) { 2094 PetscInt cStart, cEnd, c; 2095 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2096 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2097 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2098 } 2099 PetscCall(DMView_PlexExodusII(dm, viewer)); 2100 #endif 2101 #if defined(PETSC_HAVE_CGNS) 2102 } else if (iscgns) { 2103 PetscCall(DMView_PlexCGNS(dm, viewer)); 2104 #endif 2105 } else if (ispython) { 2106 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2107 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2108 /* Optionally view the partition */ 2109 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2110 if (flg) { 2111 Vec ranks; 2112 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2113 PetscCall(VecView(ranks, viewer)); 2114 PetscCall(VecDestroy(&ranks)); 2115 } 2116 /* Optionally view a label */ 2117 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2118 if (flg) { 2119 DMLabel label; 2120 Vec val; 2121 2122 PetscCall(DMGetLabel(dm, name, &label)); 2123 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2124 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2125 PetscCall(VecView(val, viewer)); 2126 PetscCall(VecDestroy(&val)); 2127 } 2128 PetscFunctionReturn(PETSC_SUCCESS); 2129 } 2130 2131 /*@ 2132 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2133 2134 Collective 2135 2136 Input Parameters: 2137 + dm - The `DM` whose topology is to be saved 2138 - viewer - The `PetscViewer` to save it in 2139 2140 Level: advanced 2141 2142 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2143 @*/ 2144 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2145 { 2146 PetscBool ishdf5; 2147 2148 PetscFunctionBegin; 2149 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2150 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2151 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2152 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2153 if (ishdf5) { 2154 #if defined(PETSC_HAVE_HDF5) 2155 PetscViewerFormat format; 2156 PetscCall(PetscViewerGetFormat(viewer, &format)); 2157 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2158 IS globalPointNumbering; 2159 2160 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2161 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2162 PetscCall(ISDestroy(&globalPointNumbering)); 2163 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2164 #else 2165 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2166 #endif 2167 } 2168 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2169 PetscFunctionReturn(PETSC_SUCCESS); 2170 } 2171 2172 /*@ 2173 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2174 2175 Collective 2176 2177 Input Parameters: 2178 + dm - The `DM` whose coordinates are to be saved 2179 - viewer - The `PetscViewer` for saving 2180 2181 Level: advanced 2182 2183 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2184 @*/ 2185 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2186 { 2187 PetscBool ishdf5; 2188 2189 PetscFunctionBegin; 2190 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2191 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2192 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2193 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2194 if (ishdf5) { 2195 #if defined(PETSC_HAVE_HDF5) 2196 PetscViewerFormat format; 2197 PetscCall(PetscViewerGetFormat(viewer, &format)); 2198 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2199 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2200 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2201 #else 2202 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2203 #endif 2204 } 2205 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2206 PetscFunctionReturn(PETSC_SUCCESS); 2207 } 2208 2209 /*@ 2210 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2211 2212 Collective 2213 2214 Input Parameters: 2215 + dm - The `DM` whose labels are to be saved 2216 - viewer - The `PetscViewer` for saving 2217 2218 Level: advanced 2219 2220 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2221 @*/ 2222 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2223 { 2224 PetscBool ishdf5; 2225 2226 PetscFunctionBegin; 2227 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2228 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2229 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2230 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2231 if (ishdf5) { 2232 #if defined(PETSC_HAVE_HDF5) 2233 IS globalPointNumbering; 2234 PetscViewerFormat format; 2235 2236 PetscCall(PetscViewerGetFormat(viewer, &format)); 2237 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2238 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2239 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2240 PetscCall(ISDestroy(&globalPointNumbering)); 2241 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2242 #else 2243 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2244 #endif 2245 } 2246 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2247 PetscFunctionReturn(PETSC_SUCCESS); 2248 } 2249 2250 /*@ 2251 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2252 2253 Collective 2254 2255 Input Parameters: 2256 + dm - The `DM` that contains the topology on which the section to be saved is defined 2257 . viewer - The `PetscViewer` for saving 2258 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2259 2260 Level: advanced 2261 2262 Notes: 2263 This function is a wrapper around `PetscSectionView()`; in addition to the raw section, it saves information that associates the section points to the topology (`dm`) points. When the topology (`dm`) and the section are later loaded with `DMPlexTopologyLoad()` and `DMPlexSectionLoad()`, respectively, this information is used to match section points with topology points. 2264 2265 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2266 2267 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2268 @*/ 2269 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2270 { 2271 PetscBool ishdf5; 2272 2273 PetscFunctionBegin; 2274 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2275 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2276 if (!sectiondm) sectiondm = dm; 2277 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2278 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2279 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2280 if (ishdf5) { 2281 #if defined(PETSC_HAVE_HDF5) 2282 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2283 #else 2284 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2285 #endif 2286 } 2287 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2288 PetscFunctionReturn(PETSC_SUCCESS); 2289 } 2290 2291 /*@ 2292 DMPlexGlobalVectorView - Saves a global vector 2293 2294 Collective 2295 2296 Input Parameters: 2297 + dm - The `DM` that represents the topology 2298 . viewer - The `PetscViewer` to save data with 2299 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2300 - vec - The global vector to be saved 2301 2302 Level: advanced 2303 2304 Notes: 2305 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2306 2307 Calling sequence: 2308 .vb 2309 DMCreate(PETSC_COMM_WORLD, &dm); 2310 DMSetType(dm, DMPLEX); 2311 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2312 DMClone(dm, §iondm); 2313 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2314 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2315 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2316 PetscSectionSetChart(section, pStart, pEnd); 2317 PetscSectionSetUp(section); 2318 DMSetLocalSection(sectiondm, section); 2319 PetscSectionDestroy(§ion); 2320 DMGetGlobalVector(sectiondm, &vec); 2321 PetscObjectSetName((PetscObject)vec, "vec_name"); 2322 DMPlexTopologyView(dm, viewer); 2323 DMPlexSectionView(dm, viewer, sectiondm); 2324 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2325 DMRestoreGlobalVector(sectiondm, &vec); 2326 DMDestroy(§iondm); 2327 DMDestroy(&dm); 2328 .ve 2329 2330 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2331 @*/ 2332 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2333 { 2334 PetscBool ishdf5; 2335 2336 PetscFunctionBegin; 2337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2338 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2339 if (!sectiondm) sectiondm = dm; 2340 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2341 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2342 /* Check consistency */ 2343 { 2344 PetscSection section; 2345 PetscBool includesConstraints; 2346 PetscInt m, m1; 2347 2348 PetscCall(VecGetLocalSize(vec, &m1)); 2349 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2350 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2351 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2352 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2353 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2354 } 2355 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2356 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2357 if (ishdf5) { 2358 #if defined(PETSC_HAVE_HDF5) 2359 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2360 #else 2361 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2362 #endif 2363 } 2364 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2365 PetscFunctionReturn(PETSC_SUCCESS); 2366 } 2367 2368 /*@ 2369 DMPlexLocalVectorView - Saves a local vector 2370 2371 Collective 2372 2373 Input Parameters: 2374 + dm - The `DM` that represents the topology 2375 . viewer - The `PetscViewer` to save data with 2376 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2377 - vec - The local vector to be saved 2378 2379 Level: advanced 2380 2381 Note: 2382 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2383 2384 Calling sequence: 2385 .vb 2386 DMCreate(PETSC_COMM_WORLD, &dm); 2387 DMSetType(dm, DMPLEX); 2388 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2389 DMClone(dm, §iondm); 2390 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2391 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2392 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2393 PetscSectionSetChart(section, pStart, pEnd); 2394 PetscSectionSetUp(section); 2395 DMSetLocalSection(sectiondm, section); 2396 DMGetLocalVector(sectiondm, &vec); 2397 PetscObjectSetName((PetscObject)vec, "vec_name"); 2398 DMPlexTopologyView(dm, viewer); 2399 DMPlexSectionView(dm, viewer, sectiondm); 2400 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2401 DMRestoreLocalVector(sectiondm, &vec); 2402 DMDestroy(§iondm); 2403 DMDestroy(&dm); 2404 .ve 2405 2406 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2407 @*/ 2408 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2409 { 2410 PetscBool ishdf5; 2411 2412 PetscFunctionBegin; 2413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2414 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2415 if (!sectiondm) sectiondm = dm; 2416 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2417 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2418 /* Check consistency */ 2419 { 2420 PetscSection section; 2421 PetscBool includesConstraints; 2422 PetscInt m, m1; 2423 2424 PetscCall(VecGetLocalSize(vec, &m1)); 2425 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2426 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2427 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2428 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2429 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2430 } 2431 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2432 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2433 if (ishdf5) { 2434 #if defined(PETSC_HAVE_HDF5) 2435 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2436 #else 2437 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2438 #endif 2439 } 2440 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2441 PetscFunctionReturn(PETSC_SUCCESS); 2442 } 2443 2444 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2445 { 2446 PetscBool ishdf5; 2447 2448 PetscFunctionBegin; 2449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2450 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2451 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2452 if (ishdf5) { 2453 #if defined(PETSC_HAVE_HDF5) 2454 PetscViewerFormat format; 2455 PetscCall(PetscViewerGetFormat(viewer, &format)); 2456 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2457 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2458 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2459 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2460 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2461 PetscFunctionReturn(PETSC_SUCCESS); 2462 #else 2463 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2464 #endif 2465 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2466 } 2467 2468 /*@ 2469 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2470 2471 Collective 2472 2473 Input Parameters: 2474 + dm - The `DM` into which the topology is loaded 2475 - viewer - The `PetscViewer` for the saved topology 2476 2477 Output Parameter: 2478 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; 2479 `NULL` if unneeded 2480 2481 Level: advanced 2482 2483 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2484 `PetscViewer`, `PetscSF` 2485 @*/ 2486 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2487 { 2488 PetscBool ishdf5; 2489 2490 PetscFunctionBegin; 2491 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2492 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2493 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2494 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2495 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2496 if (ishdf5) { 2497 #if defined(PETSC_HAVE_HDF5) 2498 PetscViewerFormat format; 2499 PetscCall(PetscViewerGetFormat(viewer, &format)); 2500 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2501 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2502 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2503 #else 2504 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2505 #endif 2506 } 2507 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2508 PetscFunctionReturn(PETSC_SUCCESS); 2509 } 2510 2511 /*@ 2512 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2513 2514 Collective 2515 2516 Input Parameters: 2517 + dm - The `DM` into which the coordinates are loaded 2518 . viewer - The `PetscViewer` for the saved coordinates 2519 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2520 2521 Level: advanced 2522 2523 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2524 `PetscSF`, `PetscViewer` 2525 @*/ 2526 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2527 { 2528 PetscBool ishdf5; 2529 2530 PetscFunctionBegin; 2531 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2532 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2533 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2534 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2535 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2536 if (ishdf5) { 2537 #if defined(PETSC_HAVE_HDF5) 2538 PetscViewerFormat format; 2539 PetscCall(PetscViewerGetFormat(viewer, &format)); 2540 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2541 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2542 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2543 #else 2544 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2545 #endif 2546 } 2547 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2548 PetscFunctionReturn(PETSC_SUCCESS); 2549 } 2550 2551 /*@ 2552 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2553 2554 Collective 2555 2556 Input Parameters: 2557 + dm - The `DM` into which the labels are loaded 2558 . viewer - The `PetscViewer` for the saved labels 2559 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2560 2561 Level: advanced 2562 2563 Note: 2564 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2565 2566 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2567 `PetscSF`, `PetscViewer` 2568 @*/ 2569 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2570 { 2571 PetscBool ishdf5; 2572 2573 PetscFunctionBegin; 2574 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2575 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2576 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2577 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2578 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2579 if (ishdf5) { 2580 #if defined(PETSC_HAVE_HDF5) 2581 PetscViewerFormat format; 2582 2583 PetscCall(PetscViewerGetFormat(viewer, &format)); 2584 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2585 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2586 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2587 #else 2588 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2589 #endif 2590 } 2591 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2592 PetscFunctionReturn(PETSC_SUCCESS); 2593 } 2594 2595 /*@ 2596 DMPlexSectionLoad - Loads section into a `DMPLEX` 2597 2598 Collective 2599 2600 Input Parameters: 2601 + dm - The `DM` that represents the topology 2602 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2603 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2604 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2605 2606 Output Parameters: 2607 + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed) 2608 - localDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed) 2609 2610 Level: advanced 2611 2612 Notes: 2613 This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2614 2615 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2616 2617 The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2618 2619 Example using 2 processes: 2620 .vb 2621 NX (number of points on dm): 4 2622 sectionA : the on-disk section 2623 vecA : a vector associated with sectionA 2624 sectionB : sectiondm's local section constructed in this function 2625 vecB (local) : a vector associated with sectiondm's local section 2626 vecB (global) : a vector associated with sectiondm's global section 2627 2628 rank 0 rank 1 2629 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2630 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2631 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2632 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2633 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2634 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2635 sectionB->atlasDof : 1 0 1 | 1 3 2636 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2637 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2638 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2639 .ve 2640 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2641 2642 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2643 @*/ 2644 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, PeOp DM sectiondm, PetscSF globalToLocalPointSF, PeOp PetscSF *globalDofSF, PeOp PetscSF *localDofSF) 2645 { 2646 PetscBool ishdf5; 2647 2648 PetscFunctionBegin; 2649 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2650 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2651 if (!sectiondm) sectiondm = dm; 2652 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2653 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2654 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2655 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2656 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2657 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2658 if (ishdf5) { 2659 #if defined(PETSC_HAVE_HDF5) 2660 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2661 #else 2662 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2663 #endif 2664 } 2665 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2666 PetscFunctionReturn(PETSC_SUCCESS); 2667 } 2668 2669 /*@ 2670 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2671 2672 Collective 2673 2674 Input Parameters: 2675 + dm - The `DM` that represents the topology 2676 . viewer - The `PetscViewer` that represents the on-disk vector data 2677 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2678 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2679 - vec - The global vector to set values of 2680 2681 Level: advanced 2682 2683 Notes: 2684 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2685 2686 Calling sequence: 2687 .vb 2688 DMCreate(PETSC_COMM_WORLD, &dm); 2689 DMSetType(dm, DMPLEX); 2690 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2691 DMPlexTopologyLoad(dm, viewer, &sfX); 2692 DMClone(dm, §iondm); 2693 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2694 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2695 DMGetGlobalVector(sectiondm, &vec); 2696 PetscObjectSetName((PetscObject)vec, "vec_name"); 2697 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2698 DMRestoreGlobalVector(sectiondm, &vec); 2699 PetscSFDestroy(&gsf); 2700 PetscSFDestroy(&sfX); 2701 DMDestroy(§iondm); 2702 DMDestroy(&dm); 2703 .ve 2704 2705 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2706 `PetscSF`, `PetscViewer` 2707 @*/ 2708 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2709 { 2710 PetscBool ishdf5; 2711 2712 PetscFunctionBegin; 2713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2714 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2715 if (!sectiondm) sectiondm = dm; 2716 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2717 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2718 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2719 /* Check consistency */ 2720 { 2721 PetscSection section; 2722 PetscBool includesConstraints; 2723 PetscInt m, m1; 2724 2725 PetscCall(VecGetLocalSize(vec, &m1)); 2726 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2727 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2728 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2729 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2730 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2731 } 2732 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2733 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2734 if (ishdf5) { 2735 #if defined(PETSC_HAVE_HDF5) 2736 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2737 #else 2738 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2739 #endif 2740 } 2741 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2742 PetscFunctionReturn(PETSC_SUCCESS); 2743 } 2744 2745 /*@ 2746 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2747 2748 Collective 2749 2750 Input Parameters: 2751 + dm - The `DM` that represents the topology 2752 . viewer - The `PetscViewer` that represents the on-disk vector data 2753 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2754 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2755 - vec - The local vector to set values of 2756 2757 Level: advanced 2758 2759 Notes: 2760 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2761 2762 Calling sequence: 2763 .vb 2764 DMCreate(PETSC_COMM_WORLD, &dm); 2765 DMSetType(dm, DMPLEX); 2766 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2767 DMPlexTopologyLoad(dm, viewer, &sfX); 2768 DMClone(dm, §iondm); 2769 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2770 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2771 DMGetLocalVector(sectiondm, &vec); 2772 PetscObjectSetName((PetscObject)vec, "vec_name"); 2773 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2774 DMRestoreLocalVector(sectiondm, &vec); 2775 PetscSFDestroy(&lsf); 2776 PetscSFDestroy(&sfX); 2777 DMDestroy(§iondm); 2778 DMDestroy(&dm); 2779 .ve 2780 2781 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2782 `PetscSF`, `PetscViewer` 2783 @*/ 2784 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2785 { 2786 PetscBool ishdf5; 2787 2788 PetscFunctionBegin; 2789 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2790 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2791 if (!sectiondm) sectiondm = dm; 2792 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2793 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2794 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2795 /* Check consistency */ 2796 { 2797 PetscSection section; 2798 PetscBool includesConstraints; 2799 PetscInt m, m1; 2800 2801 PetscCall(VecGetLocalSize(vec, &m1)); 2802 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2803 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2804 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2805 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2806 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2807 } 2808 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2809 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2810 if (ishdf5) { 2811 #if defined(PETSC_HAVE_HDF5) 2812 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2813 #else 2814 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2815 #endif 2816 } 2817 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2818 PetscFunctionReturn(PETSC_SUCCESS); 2819 } 2820 2821 PetscErrorCode DMDestroy_Plex(DM dm) 2822 { 2823 DM_Plex *mesh = (DM_Plex *)dm->data; 2824 2825 PetscFunctionBegin; 2826 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2827 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2828 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2829 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2830 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2831 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2832 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2833 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2834 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2835 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2836 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2837 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2838 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2839 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2840 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2841 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2842 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2843 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2844 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2845 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2846 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2847 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2848 PetscCall(PetscFree(mesh->cones)); 2849 PetscCall(PetscFree(mesh->coneOrientations)); 2850 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2851 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2852 PetscCall(PetscFree(mesh->supports)); 2853 PetscCall(PetscFree(mesh->cellTypes)); 2854 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2855 PetscCall(PetscFree(mesh->tetgenOpts)); 2856 PetscCall(PetscFree(mesh->triangleOpts)); 2857 PetscCall(PetscFree(mesh->transformType)); 2858 PetscCall(PetscFree(mesh->distributionName)); 2859 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2860 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2861 PetscCall(ISDestroy(&mesh->subpointIS)); 2862 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2863 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2864 if (mesh->periodic.face_sfs) { 2865 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2866 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2867 } 2868 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2869 if (mesh->periodic.periodic_points) { 2870 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2871 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2872 } 2873 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2874 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2875 PetscCall(ISDestroy(&mesh->anchorIS)); 2876 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2877 PetscCall(PetscFree(mesh->parents)); 2878 PetscCall(PetscFree(mesh->childIDs)); 2879 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2880 PetscCall(PetscFree(mesh->children)); 2881 PetscCall(DMDestroy(&mesh->referenceTree)); 2882 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2883 PetscCall(PetscFree(mesh->neighbors)); 2884 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2885 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2886 PetscCall(DMPlexTransformDestroy(&mesh->transform)); 2887 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2888 PetscCall(PetscFree(mesh)); 2889 PetscFunctionReturn(PETSC_SUCCESS); 2890 } 2891 2892 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2893 { 2894 PetscSection sectionGlobal, sectionLocal; 2895 PetscInt bs = -1, mbs; 2896 PetscInt localSize, localStart = 0; 2897 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2898 MatType mtype; 2899 ISLocalToGlobalMapping ltog; 2900 2901 PetscFunctionBegin; 2902 PetscCall(MatInitializePackage()); 2903 mtype = dm->mattype; 2904 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2905 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2906 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2907 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2908 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2909 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2910 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2911 PetscCall(MatSetType(*J, mtype)); 2912 PetscCall(MatSetFromOptions(*J)); 2913 PetscCall(MatGetBlockSize(*J, &mbs)); 2914 if (mbs > 1) bs = mbs; 2915 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2916 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2917 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2918 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2919 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2920 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2921 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2922 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2923 if (!isShell) { 2924 // There are three states with pblocks, since block starts can have no dofs: 2925 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2926 // TRUE) Block Start: The first entry in a block has been added 2927 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2928 PetscBT blst; 2929 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2930 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2931 const PetscInt *perm = NULL; 2932 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2933 PetscInt pStart, pEnd, dof, cdof, num_fields; 2934 2935 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2936 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2937 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2938 2939 PetscCall(PetscCalloc1(localSize, &pblocks)); 2940 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2941 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2942 // We need to process in the permuted order to get block sizes right 2943 for (PetscInt point = pStart; point < pEnd; ++point) { 2944 const PetscInt p = perm ? perm[point] : point; 2945 2946 switch (dm->blocking_type) { 2947 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2948 PetscInt bdof, offset; 2949 2950 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2951 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2952 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2953 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2954 if (dof > 0) { 2955 // State change 2956 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2957 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2958 2959 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2960 // Signal block concatenation 2961 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2962 } 2963 dof = dof < 0 ? -(dof + 1) : dof; 2964 bdof = cdof && (dof - cdof) ? 1 : dof; 2965 if (dof) { 2966 if (bs < 0) { 2967 bs = bdof; 2968 } else if (bs != bdof) { 2969 bs = 1; 2970 } 2971 } 2972 } break; 2973 case DM_BLOCKING_FIELD_NODE: { 2974 for (PetscInt field = 0; field < num_fields; field++) { 2975 PetscInt num_comp, bdof, offset; 2976 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2977 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2978 if (dof < 0) continue; 2979 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2980 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2981 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); 2982 PetscInt num_nodes = dof / num_comp; 2983 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2984 // Handle possibly constant block size (unlikely) 2985 bdof = cdof && (dof - cdof) ? 1 : dof; 2986 if (dof) { 2987 if (bs < 0) { 2988 bs = bdof; 2989 } else if (bs != bdof) { 2990 bs = 1; 2991 } 2992 } 2993 } 2994 } break; 2995 } 2996 } 2997 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2998 /* Must have same blocksize on all procs (some might have no points) */ 2999 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 3000 bsLocal[1] = bs; 3001 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 3002 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 3003 else bs = bsMinMax[0]; 3004 bs = PetscMax(1, bs); 3005 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 3006 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 3007 PetscCall(MatSetBlockSize(*J, bs)); 3008 PetscCall(MatSetUp(*J)); 3009 } else { 3010 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 3011 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 3012 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 3013 } 3014 if (pblocks) { // Consolidate blocks 3015 PetscInt nblocks = 0; 3016 pblocks[0] = PetscAbs(pblocks[0]); 3017 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 3018 if (pblocks[i] == 0) continue; 3019 // Negative block size indicates the blocks should be concatenated 3020 if (pblocks[i] < 0) { 3021 pblocks[i] = -pblocks[i]; 3022 pblocks[nblocks - 1] += pblocks[i]; 3023 } else { 3024 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 3025 } 3026 for (PetscInt j = 1; j < pblocks[i]; j++) 3027 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); 3028 } 3029 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 3030 } 3031 PetscCall(PetscFree(pblocks)); 3032 } 3033 PetscCall(MatSetDM(*J, dm)); 3034 PetscFunctionReturn(PETSC_SUCCESS); 3035 } 3036 3037 /*@ 3038 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 3039 3040 Not Collective 3041 3042 Input Parameter: 3043 . dm - The `DMPLEX` 3044 3045 Output Parameter: 3046 . subsection - The subdomain section 3047 3048 Level: developer 3049 3050 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 3051 @*/ 3052 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 3053 { 3054 DM_Plex *mesh = (DM_Plex *)dm->data; 3055 3056 PetscFunctionBegin; 3057 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3058 if (!mesh->subdomainSection) { 3059 PetscSection section; 3060 PetscSF sf; 3061 3062 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 3063 PetscCall(DMGetLocalSection(dm, §ion)); 3064 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 3065 PetscCall(PetscSFDestroy(&sf)); 3066 } 3067 *subsection = mesh->subdomainSection; 3068 PetscFunctionReturn(PETSC_SUCCESS); 3069 } 3070 3071 /*@ 3072 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 3073 3074 Not Collective 3075 3076 Input Parameter: 3077 . dm - The `DMPLEX` 3078 3079 Output Parameters: 3080 + pStart - The first mesh point 3081 - pEnd - The upper bound for mesh points 3082 3083 Level: beginner 3084 3085 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3086 @*/ 3087 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3088 { 3089 DM_Plex *mesh = (DM_Plex *)dm->data; 3090 3091 PetscFunctionBegin; 3092 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3093 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3094 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3095 PetscFunctionReturn(PETSC_SUCCESS); 3096 } 3097 3098 /*@ 3099 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3100 3101 Not Collective 3102 3103 Input Parameters: 3104 + dm - The `DMPLEX` 3105 . pStart - The first mesh point 3106 - pEnd - The upper bound for mesh points 3107 3108 Level: beginner 3109 3110 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3111 @*/ 3112 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3113 { 3114 DM_Plex *mesh = (DM_Plex *)dm->data; 3115 3116 PetscFunctionBegin; 3117 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3118 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3119 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3120 PetscCall(PetscFree(mesh->cellTypes)); 3121 PetscFunctionReturn(PETSC_SUCCESS); 3122 } 3123 3124 /*@ 3125 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3126 3127 Not Collective 3128 3129 Input Parameters: 3130 + dm - The `DMPLEX` 3131 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3132 3133 Output Parameter: 3134 . size - The cone size for point `p` 3135 3136 Level: beginner 3137 3138 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3139 @*/ 3140 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3141 { 3142 DM_Plex *mesh = (DM_Plex *)dm->data; 3143 3144 PetscFunctionBegin; 3145 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3146 PetscAssertPointer(size, 3); 3147 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3148 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3149 PetscFunctionReturn(PETSC_SUCCESS); 3150 } 3151 3152 /*@ 3153 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3154 3155 Not Collective 3156 3157 Input Parameters: 3158 + dm - The `DMPLEX` 3159 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3160 - size - The cone size for point `p` 3161 3162 Level: beginner 3163 3164 Note: 3165 This should be called after `DMPlexSetChart()`. 3166 3167 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3168 @*/ 3169 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3170 { 3171 DM_Plex *mesh = (DM_Plex *)dm->data; 3172 3173 PetscFunctionBegin; 3174 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3175 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3176 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3177 PetscFunctionReturn(PETSC_SUCCESS); 3178 } 3179 3180 /*@C 3181 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3182 3183 Not Collective 3184 3185 Input Parameters: 3186 + dm - The `DMPLEX` 3187 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3188 3189 Output Parameter: 3190 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3191 3192 Level: beginner 3193 3194 Fortran Notes: 3195 `cone` must be declared with 3196 .vb 3197 PetscInt, pointer :: cone(:) 3198 .ve 3199 3200 You must call `DMPlexRestoreCone()` after you finish using the array. 3201 `DMPlexRestoreCone()` is not needed/available in C. 3202 3203 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3204 @*/ 3205 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3206 { 3207 DM_Plex *mesh = (DM_Plex *)dm->data; 3208 PetscInt off; 3209 3210 PetscFunctionBegin; 3211 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3212 PetscAssertPointer(cone, 3); 3213 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3214 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3215 PetscFunctionReturn(PETSC_SUCCESS); 3216 } 3217 3218 /*@ 3219 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3220 3221 Not Collective 3222 3223 Input Parameters: 3224 + dm - The `DMPLEX` 3225 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3226 3227 Output Parameters: 3228 + pConesSection - `PetscSection` describing the layout of `pCones` 3229 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3230 3231 Level: intermediate 3232 3233 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3234 @*/ 3235 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PeOp PetscSection *pConesSection, PeOp IS *pCones) 3236 { 3237 PetscSection cs, newcs; 3238 PetscInt *cones; 3239 PetscInt *newarr = NULL; 3240 PetscInt n; 3241 3242 PetscFunctionBegin; 3243 PetscCall(DMPlexGetCones(dm, &cones)); 3244 PetscCall(DMPlexGetConeSection(dm, &cs)); 3245 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3246 if (pConesSection) *pConesSection = newcs; 3247 if (pCones) { 3248 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3249 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3250 } 3251 PetscFunctionReturn(PETSC_SUCCESS); 3252 } 3253 3254 /*@ 3255 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3256 3257 Not Collective 3258 3259 Input Parameters: 3260 + dm - The `DMPLEX` 3261 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3262 3263 Output Parameter: 3264 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3265 3266 Level: advanced 3267 3268 Notes: 3269 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3270 3271 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3272 3273 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3274 `DMPlexGetDepth()`, `IS` 3275 @*/ 3276 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3277 { 3278 IS *expandedPointsAll; 3279 PetscInt depth; 3280 3281 PetscFunctionBegin; 3282 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3283 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3284 PetscAssertPointer(expandedPoints, 3); 3285 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3286 *expandedPoints = expandedPointsAll[0]; 3287 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3288 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3289 PetscFunctionReturn(PETSC_SUCCESS); 3290 } 3291 3292 /*@ 3293 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3294 (DAG points of depth 0, i.e., without cones). 3295 3296 Not Collective 3297 3298 Input Parameters: 3299 + dm - The `DMPLEX` 3300 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3301 3302 Output Parameters: 3303 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3304 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3305 - sections - (optional) An array of sections which describe mappings from points to their cone points 3306 3307 Level: advanced 3308 3309 Notes: 3310 Like `DMPlexGetConeTuple()` but recursive. 3311 3312 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. 3313 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3314 3315 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\: 3316 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3317 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3318 3319 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3320 `DMPlexGetDepth()`, `PetscSection`, `IS` 3321 @*/ 3322 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3323 { 3324 const PetscInt *arr0 = NULL, *cone = NULL; 3325 PetscInt *arr = NULL, *newarr = NULL; 3326 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3327 IS *expandedPoints_; 3328 PetscSection *sections_; 3329 3330 PetscFunctionBegin; 3331 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3332 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3333 if (depth) PetscAssertPointer(depth, 3); 3334 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3335 if (sections) PetscAssertPointer(sections, 5); 3336 PetscCall(ISGetLocalSize(points, &n)); 3337 PetscCall(ISGetIndices(points, &arr0)); 3338 PetscCall(DMPlexGetDepth(dm, &depth_)); 3339 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3340 PetscCall(PetscCalloc1(depth_, §ions_)); 3341 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3342 for (d = depth_ - 1; d >= 0; d--) { 3343 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3344 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3345 for (i = 0; i < n; i++) { 3346 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3347 if (arr[i] >= start && arr[i] < end) { 3348 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3349 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3350 } else { 3351 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3352 } 3353 } 3354 PetscCall(PetscSectionSetUp(sections_[d])); 3355 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3356 PetscCall(PetscMalloc1(newn, &newarr)); 3357 for (i = 0; i < n; i++) { 3358 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3359 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3360 if (cn > 1) { 3361 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3362 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3363 } else { 3364 newarr[co] = arr[i]; 3365 } 3366 } 3367 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3368 arr = newarr; 3369 n = newn; 3370 } 3371 PetscCall(ISRestoreIndices(points, &arr0)); 3372 *depth = depth_; 3373 if (expandedPoints) *expandedPoints = expandedPoints_; 3374 else { 3375 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3376 PetscCall(PetscFree(expandedPoints_)); 3377 } 3378 if (sections) *sections = sections_; 3379 else { 3380 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3381 PetscCall(PetscFree(sections_)); 3382 } 3383 PetscFunctionReturn(PETSC_SUCCESS); 3384 } 3385 3386 /*@ 3387 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3388 3389 Not Collective 3390 3391 Input Parameters: 3392 + dm - The `DMPLEX` 3393 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3394 3395 Output Parameters: 3396 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3397 . expandedPoints - (optional) An array of recursively expanded cones 3398 - sections - (optional) An array of sections which describe mappings from points to their cone points 3399 3400 Level: advanced 3401 3402 Note: 3403 See `DMPlexGetConeRecursive()` 3404 3405 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3406 `DMPlexGetDepth()`, `IS`, `PetscSection` 3407 @*/ 3408 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3409 { 3410 PetscInt d, depth_; 3411 3412 PetscFunctionBegin; 3413 PetscCall(DMPlexGetDepth(dm, &depth_)); 3414 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3415 if (depth) *depth = 0; 3416 if (expandedPoints) { 3417 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3418 PetscCall(PetscFree(*expandedPoints)); 3419 } 3420 if (sections) { 3421 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3422 PetscCall(PetscFree(*sections)); 3423 } 3424 PetscFunctionReturn(PETSC_SUCCESS); 3425 } 3426 3427 /*@ 3428 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 3429 3430 Not Collective 3431 3432 Input Parameters: 3433 + dm - The `DMPLEX` 3434 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3435 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3436 3437 Level: beginner 3438 3439 Note: 3440 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3441 3442 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3443 @*/ 3444 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3445 { 3446 DM_Plex *mesh = (DM_Plex *)dm->data; 3447 PetscInt dof, off, c; 3448 3449 PetscFunctionBegin; 3450 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3451 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3452 if (dof) PetscAssertPointer(cone, 3); 3453 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3454 if (PetscDefined(USE_DEBUG)) { 3455 PetscInt pStart, pEnd; 3456 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3457 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); 3458 for (c = 0; c < dof; ++c) { 3459 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); 3460 mesh->cones[off + c] = cone[c]; 3461 } 3462 } else { 3463 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3464 } 3465 PetscFunctionReturn(PETSC_SUCCESS); 3466 } 3467 3468 /*@C 3469 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3470 3471 Not Collective 3472 3473 Input Parameters: 3474 + dm - The `DMPLEX` 3475 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3476 3477 Output Parameter: 3478 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3479 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3480 3481 Level: beginner 3482 3483 Note: 3484 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3485 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3486 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3487 with the identity. 3488 3489 Fortran Notes: 3490 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3491 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3492 3493 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3494 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3495 @*/ 3496 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3497 { 3498 DM_Plex *mesh = (DM_Plex *)dm->data; 3499 PetscInt off; 3500 3501 PetscFunctionBegin; 3502 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3503 if (PetscDefined(USE_DEBUG)) { 3504 PetscInt dof; 3505 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3506 if (dof) PetscAssertPointer(coneOrientation, 3); 3507 } 3508 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3509 3510 *coneOrientation = &mesh->coneOrientations[off]; 3511 PetscFunctionReturn(PETSC_SUCCESS); 3512 } 3513 3514 /*@ 3515 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3516 3517 Not Collective 3518 3519 Input Parameters: 3520 + dm - The `DMPLEX` 3521 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3522 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3523 3524 Level: beginner 3525 3526 Notes: 3527 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3528 3529 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3530 3531 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3532 @*/ 3533 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3534 { 3535 DM_Plex *mesh = (DM_Plex *)dm->data; 3536 PetscInt pStart, pEnd; 3537 PetscInt dof, off, c; 3538 3539 PetscFunctionBegin; 3540 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3541 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3542 if (dof) PetscAssertPointer(coneOrientation, 3); 3543 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3544 if (PetscDefined(USE_DEBUG)) { 3545 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3546 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); 3547 for (c = 0; c < dof; ++c) { 3548 PetscInt cdof, o = coneOrientation[c]; 3549 3550 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3551 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); 3552 mesh->coneOrientations[off + c] = o; 3553 } 3554 } else { 3555 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3556 } 3557 PetscFunctionReturn(PETSC_SUCCESS); 3558 } 3559 3560 /*@ 3561 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3562 3563 Not Collective 3564 3565 Input Parameters: 3566 + dm - The `DMPLEX` 3567 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3568 . conePos - The local index in the cone where the point should be put 3569 - conePoint - The mesh point to insert 3570 3571 Level: beginner 3572 3573 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3574 @*/ 3575 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3576 { 3577 DM_Plex *mesh = (DM_Plex *)dm->data; 3578 PetscInt pStart, pEnd; 3579 PetscInt dof, off; 3580 3581 PetscFunctionBegin; 3582 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3583 if (PetscDefined(USE_DEBUG)) { 3584 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3585 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); 3586 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); 3587 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3588 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); 3589 } 3590 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3591 mesh->cones[off + conePos] = conePoint; 3592 PetscFunctionReturn(PETSC_SUCCESS); 3593 } 3594 3595 /*@ 3596 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3597 3598 Not Collective 3599 3600 Input Parameters: 3601 + dm - The `DMPLEX` 3602 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3603 . conePos - The local index in the cone where the point should be put 3604 - coneOrientation - The point orientation to insert 3605 3606 Level: beginner 3607 3608 Note: 3609 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3610 3611 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3612 @*/ 3613 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3614 { 3615 DM_Plex *mesh = (DM_Plex *)dm->data; 3616 PetscInt pStart, pEnd; 3617 PetscInt dof, off; 3618 3619 PetscFunctionBegin; 3620 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3621 if (PetscDefined(USE_DEBUG)) { 3622 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3623 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); 3624 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3625 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); 3626 } 3627 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3628 mesh->coneOrientations[off + conePos] = coneOrientation; 3629 PetscFunctionReturn(PETSC_SUCCESS); 3630 } 3631 3632 /*@C 3633 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3634 3635 Not collective 3636 3637 Input Parameters: 3638 + dm - The DMPlex 3639 - p - The point, which must lie in the chart set with DMPlexSetChart() 3640 3641 Output Parameters: 3642 + cone - An array of points which are on the in-edges for point `p` 3643 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3644 integer giving the prescription for cone traversal. 3645 3646 Level: beginner 3647 3648 Notes: 3649 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3650 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3651 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3652 with the identity. 3653 3654 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3655 3656 Fortran Notes: 3657 `cone` and `ornt` must be declared with 3658 .vb 3659 PetscInt, pointer :: cone(:) 3660 PetscInt, pointer :: ornt(:) 3661 .ve 3662 3663 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3664 @*/ 3665 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, PeOp const PetscInt *cone[], PeOp const PetscInt *ornt[]) 3666 { 3667 DM_Plex *mesh = (DM_Plex *)dm->data; 3668 3669 PetscFunctionBegin; 3670 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3671 if (mesh->tr) { 3672 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3673 } else { 3674 PetscInt off; 3675 if (PetscDefined(USE_DEBUG)) { 3676 PetscInt dof; 3677 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3678 if (dof) { 3679 if (cone) PetscAssertPointer(cone, 3); 3680 if (ornt) PetscAssertPointer(ornt, 4); 3681 } 3682 } 3683 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3684 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3685 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3686 } 3687 PetscFunctionReturn(PETSC_SUCCESS); 3688 } 3689 3690 /*@C 3691 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3692 3693 Not Collective 3694 3695 Input Parameters: 3696 + dm - The DMPlex 3697 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3698 . cone - An array of points which are on the in-edges for point p 3699 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3700 integer giving the prescription for cone traversal. 3701 3702 Level: beginner 3703 3704 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3705 @*/ 3706 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3707 { 3708 DM_Plex *mesh = (DM_Plex *)dm->data; 3709 3710 PetscFunctionBegin; 3711 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3712 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3713 PetscFunctionReturn(PETSC_SUCCESS); 3714 } 3715 3716 /*@ 3717 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3718 3719 Not Collective 3720 3721 Input Parameters: 3722 + dm - The `DMPLEX` 3723 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3724 3725 Output Parameter: 3726 . size - The support size for point `p` 3727 3728 Level: beginner 3729 3730 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3731 @*/ 3732 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3733 { 3734 DM_Plex *mesh = (DM_Plex *)dm->data; 3735 3736 PetscFunctionBegin; 3737 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3738 PetscAssertPointer(size, 3); 3739 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3740 PetscFunctionReturn(PETSC_SUCCESS); 3741 } 3742 3743 /*@ 3744 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3745 3746 Not Collective 3747 3748 Input Parameters: 3749 + dm - The `DMPLEX` 3750 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3751 - size - The support size for point `p` 3752 3753 Level: beginner 3754 3755 Note: 3756 This should be called after `DMPlexSetChart()`. 3757 3758 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3759 @*/ 3760 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3761 { 3762 DM_Plex *mesh = (DM_Plex *)dm->data; 3763 3764 PetscFunctionBegin; 3765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3766 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3767 PetscFunctionReturn(PETSC_SUCCESS); 3768 } 3769 3770 /*@C 3771 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3772 3773 Not Collective 3774 3775 Input Parameters: 3776 + dm - The `DMPLEX` 3777 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3778 3779 Output Parameter: 3780 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3781 3782 Level: beginner 3783 3784 Fortran Notes: 3785 `support` must be declared with 3786 .vb 3787 PetscInt, pointer :: support(:) 3788 .ve 3789 3790 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3791 `DMPlexRestoreSupport()` is not needed/available in C. 3792 3793 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3794 @*/ 3795 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3796 { 3797 DM_Plex *mesh = (DM_Plex *)dm->data; 3798 PetscInt off; 3799 3800 PetscFunctionBegin; 3801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3802 PetscAssertPointer(support, 3); 3803 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3804 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3805 PetscFunctionReturn(PETSC_SUCCESS); 3806 } 3807 3808 /*@ 3809 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3810 3811 Not Collective 3812 3813 Input Parameters: 3814 + dm - The `DMPLEX` 3815 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3816 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3817 3818 Level: beginner 3819 3820 Note: 3821 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3822 3823 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3824 @*/ 3825 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3826 { 3827 DM_Plex *mesh = (DM_Plex *)dm->data; 3828 PetscInt pStart, pEnd; 3829 PetscInt dof, off, c; 3830 3831 PetscFunctionBegin; 3832 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3833 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3834 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3835 if (dof) PetscAssertPointer(support, 3); 3836 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3837 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); 3838 for (c = 0; c < dof; ++c) { 3839 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); 3840 mesh->supports[off + c] = support[c]; 3841 } 3842 PetscFunctionReturn(PETSC_SUCCESS); 3843 } 3844 3845 /*@ 3846 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3847 3848 Not Collective 3849 3850 Input Parameters: 3851 + dm - The `DMPLEX` 3852 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3853 . supportPos - The local index in the cone where the point should be put 3854 - supportPoint - The mesh point to insert 3855 3856 Level: beginner 3857 3858 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3859 @*/ 3860 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3861 { 3862 DM_Plex *mesh = (DM_Plex *)dm->data; 3863 PetscInt pStart, pEnd; 3864 PetscInt dof, off; 3865 3866 PetscFunctionBegin; 3867 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3868 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3869 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3870 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3871 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); 3872 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); 3873 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); 3874 mesh->supports[off + supportPos] = supportPoint; 3875 PetscFunctionReturn(PETSC_SUCCESS); 3876 } 3877 3878 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3879 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3880 { 3881 switch (ct) { 3882 case DM_POLYTOPE_SEGMENT: 3883 if (o == -1) return -2; 3884 break; 3885 case DM_POLYTOPE_TRIANGLE: 3886 if (o == -3) return -1; 3887 if (o == -2) return -3; 3888 if (o == -1) return -2; 3889 break; 3890 case DM_POLYTOPE_QUADRILATERAL: 3891 if (o == -4) return -2; 3892 if (o == -3) return -1; 3893 if (o == -2) return -4; 3894 if (o == -1) return -3; 3895 break; 3896 default: 3897 return o; 3898 } 3899 return o; 3900 } 3901 3902 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3903 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3904 { 3905 switch (ct) { 3906 case DM_POLYTOPE_SEGMENT: 3907 if ((o == -2) || (o == 1)) return -1; 3908 if (o == -1) return 0; 3909 break; 3910 case DM_POLYTOPE_TRIANGLE: 3911 if (o == -3) return -2; 3912 if (o == -2) return -1; 3913 if (o == -1) return -3; 3914 break; 3915 case DM_POLYTOPE_QUADRILATERAL: 3916 if (o == -4) return -2; 3917 if (o == -3) return -1; 3918 if (o == -2) return -4; 3919 if (o == -1) return -3; 3920 break; 3921 default: 3922 return o; 3923 } 3924 return o; 3925 } 3926 3927 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3928 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3929 { 3930 PetscInt pStart, pEnd, p; 3931 3932 PetscFunctionBegin; 3933 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3934 for (p = pStart; p < pEnd; ++p) { 3935 const PetscInt *cone, *ornt; 3936 PetscInt coneSize, c; 3937 3938 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3939 PetscCall(DMPlexGetCone(dm, p, &cone)); 3940 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3941 for (c = 0; c < coneSize; ++c) { 3942 DMPolytopeType ct; 3943 const PetscInt o = ornt[c]; 3944 3945 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3946 switch (ct) { 3947 case DM_POLYTOPE_SEGMENT: 3948 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3949 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3950 break; 3951 case DM_POLYTOPE_TRIANGLE: 3952 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3953 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3954 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3955 break; 3956 case DM_POLYTOPE_QUADRILATERAL: 3957 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3958 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3959 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3960 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3961 break; 3962 default: 3963 break; 3964 } 3965 } 3966 } 3967 PetscFunctionReturn(PETSC_SUCCESS); 3968 } 3969 3970 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3971 { 3972 DM_Plex *mesh = (DM_Plex *)dm->data; 3973 3974 PetscFunctionBeginHot; 3975 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3976 if (useCone) { 3977 PetscCall(DMPlexGetConeSize(dm, p, size)); 3978 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3979 } else { 3980 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3981 PetscCall(DMPlexGetSupport(dm, p, arr)); 3982 } 3983 } else { 3984 if (useCone) { 3985 const PetscSection s = mesh->coneSection; 3986 const PetscInt ps = p - s->pStart; 3987 const PetscInt off = s->atlasOff[ps]; 3988 3989 *size = s->atlasDof[ps]; 3990 *arr = mesh->cones + off; 3991 *ornt = mesh->coneOrientations + off; 3992 } else { 3993 const PetscSection s = mesh->supportSection; 3994 const PetscInt ps = p - s->pStart; 3995 const PetscInt off = s->atlasOff[ps]; 3996 3997 *size = s->atlasDof[ps]; 3998 *arr = mesh->supports + off; 3999 } 4000 } 4001 PetscFunctionReturn(PETSC_SUCCESS); 4002 } 4003 4004 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 4005 { 4006 DM_Plex *mesh = (DM_Plex *)dm->data; 4007 4008 PetscFunctionBeginHot; 4009 if (PetscDefined(USE_DEBUG) || mesh->tr) { 4010 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 4011 } 4012 PetscFunctionReturn(PETSC_SUCCESS); 4013 } 4014 4015 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4016 { 4017 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4018 PetscInt *closure; 4019 const PetscInt *tmp = NULL, *tmpO = NULL; 4020 PetscInt off = 0, tmpSize, t; 4021 4022 PetscFunctionBeginHot; 4023 if (ornt) { 4024 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4025 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; 4026 } 4027 if (*points) { 4028 closure = *points; 4029 } else { 4030 PetscInt maxConeSize, maxSupportSize; 4031 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4032 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 4033 } 4034 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4035 if (ct == DM_POLYTOPE_UNKNOWN) { 4036 closure[off++] = p; 4037 closure[off++] = 0; 4038 for (t = 0; t < tmpSize; ++t) { 4039 closure[off++] = tmp[t]; 4040 closure[off++] = tmpO ? tmpO[t] : 0; 4041 } 4042 } else { 4043 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 4044 4045 /* We assume that cells with a valid type have faces with a valid type */ 4046 closure[off++] = p; 4047 closure[off++] = ornt; 4048 for (t = 0; t < tmpSize; ++t) { 4049 DMPolytopeType ft; 4050 4051 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 4052 closure[off++] = tmp[arr[t]]; 4053 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 4054 } 4055 } 4056 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4057 if (numPoints) *numPoints = tmpSize + 1; 4058 if (points) *points = closure; 4059 PetscFunctionReturn(PETSC_SUCCESS); 4060 } 4061 4062 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 4063 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 4064 { 4065 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 4066 const PetscInt *cone, *ornt; 4067 PetscInt *pts, *closure = NULL; 4068 DMPolytopeType ft; 4069 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 4070 PetscInt dim, coneSize, c, d, clSize, cl; 4071 4072 PetscFunctionBeginHot; 4073 PetscCall(DMGetDimension(dm, &dim)); 4074 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4075 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4076 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4077 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4078 maxSize = PetscMax(coneSeries, supportSeries); 4079 if (*points) { 4080 pts = *points; 4081 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4082 c = 0; 4083 pts[c++] = point; 4084 pts[c++] = o; 4085 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4086 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4087 for (cl = 0; cl < clSize * 2; cl += 2) { 4088 pts[c++] = closure[cl]; 4089 pts[c++] = closure[cl + 1]; 4090 } 4091 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4092 for (cl = 0; cl < clSize * 2; cl += 2) { 4093 pts[c++] = closure[cl]; 4094 pts[c++] = closure[cl + 1]; 4095 } 4096 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4097 for (d = 2; d < coneSize; ++d) { 4098 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4099 pts[c++] = cone[arr[d * 2 + 0]]; 4100 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4101 } 4102 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4103 if (dim >= 3) { 4104 for (d = 2; d < coneSize; ++d) { 4105 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4106 const PetscInt *fcone, *fornt; 4107 PetscInt fconeSize, fc, i; 4108 4109 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4110 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4111 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4112 for (fc = 0; fc < fconeSize; ++fc) { 4113 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4114 const PetscInt co = farr[fc * 2 + 1]; 4115 4116 for (i = 0; i < c; i += 2) 4117 if (pts[i] == cp) break; 4118 if (i == c) { 4119 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4120 pts[c++] = cp; 4121 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4122 } 4123 } 4124 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4125 } 4126 } 4127 *numPoints = c / 2; 4128 *points = pts; 4129 PetscFunctionReturn(PETSC_SUCCESS); 4130 } 4131 4132 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4133 { 4134 DMPolytopeType ct; 4135 PetscInt *closure, *fifo; 4136 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4137 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4138 PetscInt depth, maxSize; 4139 4140 PetscFunctionBeginHot; 4141 PetscCall(DMPlexGetDepth(dm, &depth)); 4142 if (depth == 1) { 4143 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4144 PetscFunctionReturn(PETSC_SUCCESS); 4145 } 4146 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4147 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; 4148 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4149 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4150 PetscFunctionReturn(PETSC_SUCCESS); 4151 } 4152 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4153 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4154 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4155 maxSize = PetscMax(coneSeries, supportSeries); 4156 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4157 if (*points) { 4158 closure = *points; 4159 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4160 closure[closureSize++] = p; 4161 closure[closureSize++] = ornt; 4162 fifo[fifoSize++] = p; 4163 fifo[fifoSize++] = ornt; 4164 fifo[fifoSize++] = ct; 4165 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4166 while (fifoSize - fifoStart) { 4167 const PetscInt q = fifo[fifoStart++]; 4168 const PetscInt o = fifo[fifoStart++]; 4169 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4170 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4171 const PetscInt *tmp, *tmpO = NULL; 4172 PetscInt tmpSize, t; 4173 4174 if (PetscDefined(USE_DEBUG)) { 4175 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4176 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); 4177 } 4178 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4179 for (t = 0; t < tmpSize; ++t) { 4180 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4181 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4182 const PetscInt cp = tmp[ip]; 4183 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4184 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4185 PetscInt c; 4186 4187 /* Check for duplicate */ 4188 for (c = 0; c < closureSize; c += 2) { 4189 if (closure[c] == cp) break; 4190 } 4191 if (c == closureSize) { 4192 closure[closureSize++] = cp; 4193 closure[closureSize++] = co; 4194 fifo[fifoSize++] = cp; 4195 fifo[fifoSize++] = co; 4196 fifo[fifoSize++] = ct; 4197 } 4198 } 4199 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4200 } 4201 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4202 if (numPoints) *numPoints = closureSize / 2; 4203 if (points) *points = closure; 4204 PetscFunctionReturn(PETSC_SUCCESS); 4205 } 4206 4207 /*@C 4208 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4209 4210 Not Collective 4211 4212 Input Parameters: 4213 + dm - The `DMPLEX` 4214 . p - The mesh point 4215 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4216 4217 Input/Output Parameter: 4218 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4219 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4220 otherwise the provided array is used to hold the values 4221 4222 Output Parameter: 4223 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4224 4225 Level: beginner 4226 4227 Note: 4228 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4229 4230 Fortran Notes: 4231 `points` must be declared with 4232 .vb 4233 PetscInt, pointer :: points(:) 4234 .ve 4235 and is always allocated by the function. 4236 4237 Pass `PETSC_NULL_INTEGER` for `numPoints` if it is not needed 4238 4239 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4240 @*/ 4241 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4242 { 4243 PetscFunctionBeginHot; 4244 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4245 if (numPoints) PetscAssertPointer(numPoints, 4); 4246 if (points) PetscAssertPointer(points, 5); 4247 if (PetscDefined(USE_DEBUG)) { 4248 PetscInt pStart, pEnd; 4249 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4250 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); 4251 } 4252 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4253 PetscFunctionReturn(PETSC_SUCCESS); 4254 } 4255 4256 /*@C 4257 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4258 4259 Not Collective 4260 4261 Input Parameters: 4262 + dm - The `DMPLEX` 4263 . p - The mesh point 4264 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4265 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4266 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4267 4268 Level: beginner 4269 4270 Note: 4271 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4272 4273 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4274 @*/ 4275 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4276 { 4277 PetscFunctionBeginHot; 4278 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4279 if (numPoints) *numPoints = 0; 4280 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4281 PetscFunctionReturn(PETSC_SUCCESS); 4282 } 4283 4284 /*@ 4285 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4286 4287 Not Collective 4288 4289 Input Parameter: 4290 . dm - The `DMPLEX` 4291 4292 Output Parameters: 4293 + maxConeSize - The maximum number of in-edges 4294 - maxSupportSize - The maximum number of out-edges 4295 4296 Level: beginner 4297 4298 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4299 @*/ 4300 PetscErrorCode DMPlexGetMaxSizes(DM dm, PeOp PetscInt *maxConeSize, PeOp PetscInt *maxSupportSize) 4301 { 4302 DM_Plex *mesh = (DM_Plex *)dm->data; 4303 4304 PetscFunctionBegin; 4305 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4306 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4307 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4308 PetscFunctionReturn(PETSC_SUCCESS); 4309 } 4310 4311 PetscErrorCode DMSetUp_Plex(DM dm) 4312 { 4313 DM_Plex *mesh = (DM_Plex *)dm->data; 4314 PetscInt size, maxSupportSize; 4315 4316 PetscFunctionBegin; 4317 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4318 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4319 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4320 PetscCall(PetscMalloc1(size, &mesh->cones)); 4321 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4322 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4323 if (maxSupportSize) { 4324 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4325 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4326 PetscCall(PetscMalloc1(size, &mesh->supports)); 4327 } 4328 PetscFunctionReturn(PETSC_SUCCESS); 4329 } 4330 4331 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4332 { 4333 PetscFunctionBegin; 4334 if (subdm) PetscCall(DMClone(dm, subdm)); 4335 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4336 if (subdm) (*subdm)->useNatural = dm->useNatural; 4337 if (dm->useNatural && dm->sfMigration) { 4338 PetscSF sfNatural; 4339 4340 (*subdm)->sfMigration = dm->sfMigration; 4341 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4342 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4343 (*subdm)->sfNatural = sfNatural; 4344 } 4345 PetscFunctionReturn(PETSC_SUCCESS); 4346 } 4347 4348 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4349 { 4350 PetscInt i = 0; 4351 4352 PetscFunctionBegin; 4353 PetscCall(DMClone(dms[0], superdm)); 4354 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4355 (*superdm)->useNatural = PETSC_FALSE; 4356 for (i = 0; i < len; i++) { 4357 if (dms[i]->useNatural && dms[i]->sfMigration) { 4358 PetscSF sfNatural; 4359 4360 (*superdm)->sfMigration = dms[i]->sfMigration; 4361 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4362 (*superdm)->useNatural = PETSC_TRUE; 4363 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4364 (*superdm)->sfNatural = sfNatural; 4365 break; 4366 } 4367 } 4368 PetscFunctionReturn(PETSC_SUCCESS); 4369 } 4370 4371 /*@ 4372 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4373 4374 Not Collective 4375 4376 Input Parameter: 4377 . dm - The `DMPLEX` 4378 4379 Level: beginner 4380 4381 Note: 4382 This should be called after all calls to `DMPlexSetCone()` 4383 4384 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4385 @*/ 4386 PetscErrorCode DMPlexSymmetrize(DM dm) 4387 { 4388 DM_Plex *mesh = (DM_Plex *)dm->data; 4389 PetscInt *offsets; 4390 PetscInt supportSize; 4391 PetscInt pStart, pEnd, p; 4392 4393 PetscFunctionBegin; 4394 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4395 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4396 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4397 /* Calculate support sizes */ 4398 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4399 for (p = pStart; p < pEnd; ++p) { 4400 PetscInt dof, off, c; 4401 4402 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4403 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4404 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4405 } 4406 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4407 /* Calculate supports */ 4408 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4409 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4410 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4411 for (p = pStart; p < pEnd; ++p) { 4412 PetscInt dof, off, c; 4413 4414 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4415 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4416 for (c = off; c < off + dof; ++c) { 4417 const PetscInt q = mesh->cones[c]; 4418 PetscInt offS; 4419 4420 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4421 4422 mesh->supports[offS + offsets[q]] = p; 4423 ++offsets[q]; 4424 } 4425 } 4426 PetscCall(PetscFree(offsets)); 4427 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4428 PetscFunctionReturn(PETSC_SUCCESS); 4429 } 4430 4431 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4432 { 4433 IS stratumIS; 4434 4435 PetscFunctionBegin; 4436 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4437 if (PetscDefined(USE_DEBUG)) { 4438 PetscInt qStart, qEnd, numLevels, level; 4439 PetscBool overlap = PETSC_FALSE; 4440 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4441 for (level = 0; level < numLevels; level++) { 4442 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4443 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4444 overlap = PETSC_TRUE; 4445 break; 4446 } 4447 } 4448 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); 4449 } 4450 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4451 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4452 PetscCall(ISDestroy(&stratumIS)); 4453 PetscFunctionReturn(PETSC_SUCCESS); 4454 } 4455 4456 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4457 { 4458 PetscInt *pMin, *pMax; 4459 PetscInt pStart, pEnd; 4460 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4461 4462 PetscFunctionBegin; 4463 { 4464 DMLabel label2; 4465 4466 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4467 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4468 } 4469 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4470 for (PetscInt p = pStart; p < pEnd; ++p) { 4471 DMPolytopeType ct; 4472 4473 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4474 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4475 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4476 } 4477 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4478 for (PetscInt d = dmin; d <= dmax; ++d) { 4479 pMin[d] = PETSC_INT_MAX; 4480 pMax[d] = PETSC_INT_MIN; 4481 } 4482 for (PetscInt p = pStart; p < pEnd; ++p) { 4483 DMPolytopeType ct; 4484 PetscInt d; 4485 4486 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4487 d = DMPolytopeTypeGetDim(ct); 4488 pMin[d] = PetscMin(p, pMin[d]); 4489 pMax[d] = PetscMax(p, pMax[d]); 4490 } 4491 for (PetscInt d = dmin; d <= dmax; ++d) { 4492 if (pMin[d] > pMax[d]) continue; 4493 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4494 } 4495 PetscCall(PetscFree2(pMin, pMax)); 4496 PetscFunctionReturn(PETSC_SUCCESS); 4497 } 4498 4499 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4500 { 4501 PetscInt pStart, pEnd; 4502 PetscInt numRoots = 0, numLeaves = 0; 4503 4504 PetscFunctionBegin; 4505 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4506 { 4507 /* Initialize roots and count leaves */ 4508 PetscInt sMin = PETSC_INT_MAX; 4509 PetscInt sMax = PETSC_INT_MIN; 4510 PetscInt coneSize, supportSize; 4511 4512 for (PetscInt p = pStart; p < pEnd; ++p) { 4513 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4514 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4515 if (!coneSize && supportSize) { 4516 sMin = PetscMin(p, sMin); 4517 sMax = PetscMax(p, sMax); 4518 ++numRoots; 4519 } else if (!supportSize && coneSize) { 4520 ++numLeaves; 4521 } else if (!supportSize && !coneSize) { 4522 /* Isolated points */ 4523 sMin = PetscMin(p, sMin); 4524 sMax = PetscMax(p, sMax); 4525 } 4526 } 4527 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4528 } 4529 4530 if (numRoots + numLeaves == (pEnd - pStart)) { 4531 PetscInt sMin = PETSC_INT_MAX; 4532 PetscInt sMax = PETSC_INT_MIN; 4533 PetscInt coneSize, supportSize; 4534 4535 for (PetscInt p = pStart; p < pEnd; ++p) { 4536 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4537 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4538 if (!supportSize && coneSize) { 4539 sMin = PetscMin(p, sMin); 4540 sMax = PetscMax(p, sMax); 4541 } 4542 } 4543 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4544 } else { 4545 PetscInt level = 0; 4546 PetscInt qStart, qEnd; 4547 4548 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4549 while (qEnd > qStart) { 4550 PetscInt sMin = PETSC_INT_MAX; 4551 PetscInt sMax = PETSC_INT_MIN; 4552 4553 for (PetscInt q = qStart; q < qEnd; ++q) { 4554 const PetscInt *support; 4555 PetscInt supportSize; 4556 4557 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4558 PetscCall(DMPlexGetSupport(dm, q, &support)); 4559 for (PetscInt s = 0; s < supportSize; ++s) { 4560 sMin = PetscMin(support[s], sMin); 4561 sMax = PetscMax(support[s], sMax); 4562 } 4563 } 4564 PetscCall(DMLabelGetNumValues(label, &level)); 4565 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4566 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4567 } 4568 } 4569 PetscFunctionReturn(PETSC_SUCCESS); 4570 } 4571 4572 /*@ 4573 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4574 4575 Collective 4576 4577 Input Parameter: 4578 . dm - The `DMPLEX` 4579 4580 Level: beginner 4581 4582 Notes: 4583 The strata group all points of the same grade, and this function calculates the strata. This 4584 grade can be seen as the height (or depth) of the point in the DAG. 4585 4586 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4587 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4588 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4589 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4590 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4591 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4592 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4593 4594 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4595 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4596 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 4597 to interpolate only that one (e0), so that 4598 .vb 4599 cone(c0) = {e0, v2} 4600 cone(e0) = {v0, v1} 4601 .ve 4602 If `DMPlexStratify()` is run on this mesh, it will give depths 4603 .vb 4604 depth 0 = {v0, v1, v2} 4605 depth 1 = {e0, c0} 4606 .ve 4607 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4608 4609 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4610 4611 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4612 @*/ 4613 PetscErrorCode DMPlexStratify(DM dm) 4614 { 4615 DM_Plex *mesh = (DM_Plex *)dm->data; 4616 DMLabel label; 4617 PetscBool flg = PETSC_FALSE; 4618 4619 PetscFunctionBegin; 4620 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4621 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4622 4623 // Create depth label 4624 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4625 PetscCall(DMCreateLabel(dm, "depth")); 4626 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4627 4628 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4629 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4630 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4631 4632 { /* just in case there is an empty process */ 4633 PetscInt numValues, maxValues = 0, v; 4634 4635 PetscCall(DMLabelGetNumValues(label, &numValues)); 4636 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4637 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4638 } 4639 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4640 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4641 PetscFunctionReturn(PETSC_SUCCESS); 4642 } 4643 4644 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4645 { 4646 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4647 PetscInt dim, depth, pheight, coneSize; 4648 PetscBool preferTensor; 4649 4650 PetscFunctionBeginHot; 4651 PetscCall(DMGetDimension(dm, &dim)); 4652 PetscCall(DMPlexGetDepth(dm, &depth)); 4653 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4654 PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor)); 4655 pheight = depth - pdepth; 4656 if (depth <= 1) { 4657 switch (pdepth) { 4658 case 0: 4659 ct = DM_POLYTOPE_POINT; 4660 break; 4661 case 1: 4662 switch (coneSize) { 4663 case 2: 4664 ct = DM_POLYTOPE_SEGMENT; 4665 break; 4666 case 3: 4667 ct = DM_POLYTOPE_TRIANGLE; 4668 break; 4669 case 4: 4670 switch (dim) { 4671 case 2: 4672 ct = DM_POLYTOPE_QUADRILATERAL; 4673 break; 4674 case 3: 4675 ct = DM_POLYTOPE_TETRAHEDRON; 4676 break; 4677 default: 4678 break; 4679 } 4680 break; 4681 case 5: 4682 ct = DM_POLYTOPE_PYRAMID; 4683 break; 4684 case 6: 4685 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4686 break; 4687 case 8: 4688 ct = DM_POLYTOPE_HEXAHEDRON; 4689 break; 4690 default: 4691 break; 4692 } 4693 } 4694 } else { 4695 if (pdepth == 0) { 4696 ct = DM_POLYTOPE_POINT; 4697 } else if (pheight == 0) { 4698 switch (dim) { 4699 case 1: 4700 switch (coneSize) { 4701 case 2: 4702 ct = DM_POLYTOPE_SEGMENT; 4703 break; 4704 default: 4705 break; 4706 } 4707 break; 4708 case 2: 4709 switch (coneSize) { 4710 case 3: 4711 ct = DM_POLYTOPE_TRIANGLE; 4712 break; 4713 case 4: 4714 ct = DM_POLYTOPE_QUADRILATERAL; 4715 break; 4716 default: 4717 break; 4718 } 4719 break; 4720 case 3: 4721 switch (coneSize) { 4722 case 4: 4723 ct = DM_POLYTOPE_TETRAHEDRON; 4724 break; 4725 case 5: { 4726 const PetscInt *cone; 4727 PetscInt faceConeSize; 4728 4729 PetscCall(DMPlexGetCone(dm, p, &cone)); 4730 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4731 switch (faceConeSize) { 4732 case 3: 4733 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4734 break; 4735 case 4: 4736 ct = DM_POLYTOPE_PYRAMID; 4737 break; 4738 } 4739 } break; 4740 case 6: 4741 ct = DM_POLYTOPE_HEXAHEDRON; 4742 break; 4743 default: 4744 break; 4745 } 4746 break; 4747 default: 4748 break; 4749 } 4750 } else if (pheight > 0) { 4751 switch (coneSize) { 4752 case 2: 4753 ct = DM_POLYTOPE_SEGMENT; 4754 break; 4755 case 3: 4756 ct = DM_POLYTOPE_TRIANGLE; 4757 break; 4758 case 4: 4759 ct = DM_POLYTOPE_QUADRILATERAL; 4760 break; 4761 default: 4762 break; 4763 } 4764 } 4765 } 4766 *pt = ct; 4767 PetscFunctionReturn(PETSC_SUCCESS); 4768 } 4769 4770 /*@ 4771 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4772 4773 Collective 4774 4775 Input Parameter: 4776 . dm - The `DMPLEX` 4777 4778 Level: developer 4779 4780 Note: 4781 This function is normally called automatically when a cell type is requested. It creates an 4782 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4783 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4784 4785 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4786 4787 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4788 @*/ 4789 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4790 { 4791 DM_Plex *mesh; 4792 DMLabel ctLabel; 4793 PetscInt pStart, pEnd, p; 4794 4795 PetscFunctionBegin; 4796 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4797 mesh = (DM_Plex *)dm->data; 4798 PetscCall(DMCreateLabel(dm, "celltype")); 4799 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4800 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4801 PetscCall(PetscFree(mesh->cellTypes)); 4802 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4803 for (p = pStart; p < pEnd; ++p) { 4804 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4805 PetscInt pdepth; 4806 4807 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4808 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4809 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]); 4810 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4811 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4812 } 4813 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4814 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4815 PetscFunctionReturn(PETSC_SUCCESS); 4816 } 4817 4818 /*@C 4819 DMPlexGetJoin - Get an array for the join of the set of points 4820 4821 Not Collective 4822 4823 Input Parameters: 4824 + dm - The `DMPLEX` object 4825 . numPoints - The number of input points for the join 4826 - points - The input points 4827 4828 Output Parameters: 4829 + numCoveredPoints - The number of points in the join 4830 - coveredPoints - The points in the join 4831 4832 Level: intermediate 4833 4834 Note: 4835 Currently, this is restricted to a single level join 4836 4837 Fortran Notes: 4838 `converedPoints` must be declared with 4839 .vb 4840 PetscInt, pointer :: coveredPints(:) 4841 .ve 4842 4843 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4844 @*/ 4845 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4846 { 4847 DM_Plex *mesh = (DM_Plex *)dm->data; 4848 PetscInt *join[2]; 4849 PetscInt joinSize, i = 0; 4850 PetscInt dof, off, p, c, m; 4851 PetscInt maxSupportSize; 4852 4853 PetscFunctionBegin; 4854 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4855 PetscAssertPointer(points, 3); 4856 PetscAssertPointer(numCoveredPoints, 4); 4857 PetscAssertPointer(coveredPoints, 5); 4858 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4859 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4860 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4861 /* Copy in support of first point */ 4862 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4863 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4864 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4865 /* Check each successive support */ 4866 for (p = 1; p < numPoints; ++p) { 4867 PetscInt newJoinSize = 0; 4868 4869 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4870 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4871 for (c = 0; c < dof; ++c) { 4872 const PetscInt point = mesh->supports[off + c]; 4873 4874 for (m = 0; m < joinSize; ++m) { 4875 if (point == join[i][m]) { 4876 join[1 - i][newJoinSize++] = point; 4877 break; 4878 } 4879 } 4880 } 4881 joinSize = newJoinSize; 4882 i = 1 - i; 4883 } 4884 *numCoveredPoints = joinSize; 4885 *coveredPoints = join[i]; 4886 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4887 PetscFunctionReturn(PETSC_SUCCESS); 4888 } 4889 4890 /*@C 4891 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4892 4893 Not Collective 4894 4895 Input Parameters: 4896 + dm - The `DMPLEX` object 4897 . numPoints - The number of input points for the join 4898 - points - The input points 4899 4900 Output Parameters: 4901 + numCoveredPoints - The number of points in the join 4902 - coveredPoints - The points in the join 4903 4904 Level: intermediate 4905 4906 Fortran Notes: 4907 `converedPoints` must be declared with 4908 .vb 4909 PetscInt, pointer :: coveredPoints(:) 4910 .ve 4911 4912 Pass `PETSC_NULL_INTEGER` for `numCoveredPoints` if it is not needed 4913 4914 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4915 @*/ 4916 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4917 { 4918 PetscFunctionBegin; 4919 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4920 if (points) PetscAssertPointer(points, 3); 4921 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4922 PetscAssertPointer(coveredPoints, 5); 4923 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4924 if (numCoveredPoints) *numCoveredPoints = 0; 4925 PetscFunctionReturn(PETSC_SUCCESS); 4926 } 4927 4928 /*@C 4929 DMPlexGetFullJoin - Get an array for the join of the set of points 4930 4931 Not Collective 4932 4933 Input Parameters: 4934 + dm - The `DMPLEX` object 4935 . numPoints - The number of input points for the join 4936 - points - The input points, its length is `numPoints` 4937 4938 Output Parameters: 4939 + numCoveredPoints - The number of points in the join 4940 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4941 4942 Level: intermediate 4943 4944 Fortran Notes: 4945 .vb 4946 PetscInt, pointer :: coveredPints(:) 4947 .ve 4948 4949 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4950 @*/ 4951 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4952 { 4953 PetscInt *offsets, **closures; 4954 PetscInt *join[2]; 4955 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4956 PetscInt p, d, c, m, ms; 4957 4958 PetscFunctionBegin; 4959 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4960 PetscAssertPointer(points, 3); 4961 PetscAssertPointer(numCoveredPoints, 4); 4962 PetscAssertPointer(coveredPoints, 5); 4963 4964 PetscCall(DMPlexGetDepth(dm, &depth)); 4965 PetscCall(PetscCalloc1(numPoints, &closures)); 4966 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4967 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4968 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4969 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4970 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4971 4972 for (p = 0; p < numPoints; ++p) { 4973 PetscInt closureSize; 4974 4975 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4976 4977 offsets[p * (depth + 2) + 0] = 0; 4978 for (d = 0; d < depth + 1; ++d) { 4979 PetscInt pStart, pEnd, i; 4980 4981 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4982 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4983 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4984 offsets[p * (depth + 2) + d + 1] = i; 4985 break; 4986 } 4987 } 4988 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4989 } 4990 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); 4991 } 4992 for (d = 0; d < depth + 1; ++d) { 4993 PetscInt dof; 4994 4995 /* Copy in support of first point */ 4996 dof = offsets[d + 1] - offsets[d]; 4997 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4998 /* Check each successive cone */ 4999 for (p = 1; p < numPoints && joinSize; ++p) { 5000 PetscInt newJoinSize = 0; 5001 5002 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 5003 for (c = 0; c < dof; ++c) { 5004 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 5005 5006 for (m = 0; m < joinSize; ++m) { 5007 if (point == join[i][m]) { 5008 join[1 - i][newJoinSize++] = point; 5009 break; 5010 } 5011 } 5012 } 5013 joinSize = newJoinSize; 5014 i = 1 - i; 5015 } 5016 if (joinSize) break; 5017 } 5018 *numCoveredPoints = joinSize; 5019 *coveredPoints = join[i]; 5020 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 5021 PetscCall(PetscFree(closures)); 5022 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 5023 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 5024 PetscFunctionReturn(PETSC_SUCCESS); 5025 } 5026 5027 /*@C 5028 DMPlexGetMeet - Get an array for the meet of the set of points 5029 5030 Not Collective 5031 5032 Input Parameters: 5033 + dm - The `DMPLEX` object 5034 . numPoints - The number of input points for the meet 5035 - points - The input points, of length `numPoints` 5036 5037 Output Parameters: 5038 + numCoveringPoints - The number of points in the meet 5039 - coveringPoints - The points in the meet, of length `numCoveringPoints` 5040 5041 Level: intermediate 5042 5043 Note: 5044 Currently, this is restricted to a single level meet 5045 5046 Fortran Note: 5047 `coveringPoints` must be declared with 5048 .vb 5049 PetscInt, pointer :: coveringPoints(:) 5050 .ve 5051 5052 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5053 @*/ 5054 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 5055 { 5056 DM_Plex *mesh = (DM_Plex *)dm->data; 5057 PetscInt *meet[2]; 5058 PetscInt meetSize, i = 0; 5059 PetscInt dof, off, p, c, m; 5060 PetscInt maxConeSize; 5061 5062 PetscFunctionBegin; 5063 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5064 PetscAssertPointer(points, 3); 5065 PetscAssertPointer(numCoveringPoints, 4); 5066 PetscAssertPointer(coveringPoints, 5); 5067 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 5068 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 5069 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 5070 /* Copy in cone of first point */ 5071 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 5072 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 5073 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5074 /* Check each successive cone */ 5075 for (p = 1; p < numPoints; ++p) { 5076 PetscInt newMeetSize = 0; 5077 5078 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5079 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5080 for (c = 0; c < dof; ++c) { 5081 const PetscInt point = mesh->cones[off + c]; 5082 5083 for (m = 0; m < meetSize; ++m) { 5084 if (point == meet[i][m]) { 5085 meet[1 - i][newMeetSize++] = point; 5086 break; 5087 } 5088 } 5089 } 5090 meetSize = newMeetSize; 5091 i = 1 - i; 5092 } 5093 *numCoveringPoints = meetSize; 5094 *coveringPoints = meet[i]; 5095 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5096 PetscFunctionReturn(PETSC_SUCCESS); 5097 } 5098 5099 /*@C 5100 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5101 5102 Not Collective 5103 5104 Input Parameters: 5105 + dm - The `DMPLEX` object 5106 . numPoints - The number of input points for the meet 5107 - points - The input points 5108 5109 Output Parameters: 5110 + numCoveredPoints - The number of points in the meet 5111 - coveredPoints - The points in the meet 5112 5113 Level: intermediate 5114 5115 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5116 @*/ 5117 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5118 { 5119 PetscFunctionBegin; 5120 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5121 if (points) PetscAssertPointer(points, 3); 5122 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5123 PetscAssertPointer(coveredPoints, 5); 5124 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5125 if (numCoveredPoints) *numCoveredPoints = 0; 5126 PetscFunctionReturn(PETSC_SUCCESS); 5127 } 5128 5129 /*@C 5130 DMPlexGetFullMeet - Get an array for the meet of the set of points 5131 5132 Not Collective 5133 5134 Input Parameters: 5135 + dm - The `DMPLEX` object 5136 . numPoints - The number of input points for the meet 5137 - points - The input points, of length `numPoints` 5138 5139 Output Parameters: 5140 + numCoveredPoints - The number of points in the meet 5141 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5142 5143 Level: intermediate 5144 5145 Fortran Notes: 5146 `coveredPoints` must be declared with 5147 .vb 5148 PetscInt, pointer :: coveredPoints(:) 5149 .ve 5150 5151 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5152 @*/ 5153 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5154 { 5155 PetscInt *offsets, **closures; 5156 PetscInt *meet[2]; 5157 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5158 PetscInt p, h, c, m, mc; 5159 5160 PetscFunctionBegin; 5161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5162 PetscAssertPointer(points, 3); 5163 PetscAssertPointer(numCoveredPoints, 4); 5164 PetscAssertPointer(coveredPoints, 5); 5165 5166 PetscCall(DMPlexGetDepth(dm, &height)); 5167 PetscCall(PetscMalloc1(numPoints, &closures)); 5168 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5169 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5170 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5171 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5172 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5173 5174 for (p = 0; p < numPoints; ++p) { 5175 PetscInt closureSize; 5176 5177 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5178 5179 offsets[p * (height + 2) + 0] = 0; 5180 for (h = 0; h < height + 1; ++h) { 5181 PetscInt pStart, pEnd, i; 5182 5183 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5184 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5185 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5186 offsets[p * (height + 2) + h + 1] = i; 5187 break; 5188 } 5189 } 5190 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5191 } 5192 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); 5193 } 5194 for (h = 0; h < height + 1; ++h) { 5195 PetscInt dof; 5196 5197 /* Copy in cone of first point */ 5198 dof = offsets[h + 1] - offsets[h]; 5199 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5200 /* Check each successive cone */ 5201 for (p = 1; p < numPoints && meetSize; ++p) { 5202 PetscInt newMeetSize = 0; 5203 5204 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5205 for (c = 0; c < dof; ++c) { 5206 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5207 5208 for (m = 0; m < meetSize; ++m) { 5209 if (point == meet[i][m]) { 5210 meet[1 - i][newMeetSize++] = point; 5211 break; 5212 } 5213 } 5214 } 5215 meetSize = newMeetSize; 5216 i = 1 - i; 5217 } 5218 if (meetSize) break; 5219 } 5220 *numCoveredPoints = meetSize; 5221 *coveredPoints = meet[i]; 5222 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5223 PetscCall(PetscFree(closures)); 5224 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5225 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5226 PetscFunctionReturn(PETSC_SUCCESS); 5227 } 5228 5229 /*@ 5230 DMPlexEqual - Determine if two `DM` have the same topology 5231 5232 Not Collective 5233 5234 Input Parameters: 5235 + dmA - A `DMPLEX` object 5236 - dmB - A `DMPLEX` object 5237 5238 Output Parameter: 5239 . equal - `PETSC_TRUE` if the topologies are identical 5240 5241 Level: intermediate 5242 5243 Note: 5244 We are not solving graph isomorphism, so we do not permute. 5245 5246 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5247 @*/ 5248 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5249 { 5250 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5251 5252 PetscFunctionBegin; 5253 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5254 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5255 PetscAssertPointer(equal, 3); 5256 5257 *equal = PETSC_FALSE; 5258 PetscCall(DMPlexGetDepth(dmA, &depth)); 5259 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5260 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5261 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5262 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5263 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5264 for (p = pStart; p < pEnd; ++p) { 5265 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5266 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5267 5268 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5269 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5270 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5271 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5272 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5273 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5274 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5275 for (c = 0; c < coneSize; ++c) { 5276 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5277 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5278 } 5279 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5280 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5281 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5282 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5283 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5284 for (s = 0; s < supportSize; ++s) { 5285 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5286 } 5287 } 5288 *equal = PETSC_TRUE; 5289 PetscFunctionReturn(PETSC_SUCCESS); 5290 } 5291 5292 /*@ 5293 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5294 5295 Not Collective 5296 5297 Input Parameters: 5298 + dm - The `DMPLEX` 5299 . cellDim - The cell dimension 5300 - numCorners - The number of vertices on a cell 5301 5302 Output Parameter: 5303 . numFaceVertices - The number of vertices on a face 5304 5305 Level: developer 5306 5307 Note: 5308 Of course this can only work for a restricted set of symmetric shapes 5309 5310 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5311 @*/ 5312 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5313 { 5314 MPI_Comm comm; 5315 5316 PetscFunctionBegin; 5317 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5318 PetscAssertPointer(numFaceVertices, 4); 5319 switch (cellDim) { 5320 case 0: 5321 *numFaceVertices = 0; 5322 break; 5323 case 1: 5324 *numFaceVertices = 1; 5325 break; 5326 case 2: 5327 switch (numCorners) { 5328 case 3: /* triangle */ 5329 *numFaceVertices = 2; /* Edge has 2 vertices */ 5330 break; 5331 case 4: /* quadrilateral */ 5332 *numFaceVertices = 2; /* Edge has 2 vertices */ 5333 break; 5334 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5335 *numFaceVertices = 3; /* Edge has 3 vertices */ 5336 break; 5337 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5338 *numFaceVertices = 3; /* Edge has 3 vertices */ 5339 break; 5340 default: 5341 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5342 } 5343 break; 5344 case 3: 5345 switch (numCorners) { 5346 case 4: /* tetradehdron */ 5347 *numFaceVertices = 3; /* Face has 3 vertices */ 5348 break; 5349 case 6: /* tet cohesive cells */ 5350 *numFaceVertices = 4; /* Face has 4 vertices */ 5351 break; 5352 case 8: /* hexahedron */ 5353 *numFaceVertices = 4; /* Face has 4 vertices */ 5354 break; 5355 case 9: /* tet cohesive Lagrange cells */ 5356 *numFaceVertices = 6; /* Face has 6 vertices */ 5357 break; 5358 case 10: /* quadratic tetrahedron */ 5359 *numFaceVertices = 6; /* Face has 6 vertices */ 5360 break; 5361 case 12: /* hex cohesive Lagrange cells */ 5362 *numFaceVertices = 6; /* Face has 6 vertices */ 5363 break; 5364 case 18: /* quadratic tet cohesive Lagrange cells */ 5365 *numFaceVertices = 6; /* Face has 6 vertices */ 5366 break; 5367 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5368 *numFaceVertices = 9; /* Face has 9 vertices */ 5369 break; 5370 default: 5371 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5372 } 5373 break; 5374 default: 5375 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5376 } 5377 PetscFunctionReturn(PETSC_SUCCESS); 5378 } 5379 5380 /*@ 5381 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5382 5383 Not Collective 5384 5385 Input Parameter: 5386 . dm - The `DMPLEX` object 5387 5388 Output Parameter: 5389 . depthLabel - The `DMLabel` recording point depth 5390 5391 Level: developer 5392 5393 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5394 @*/ 5395 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5396 { 5397 PetscFunctionBegin; 5398 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5399 PetscAssertPointer(depthLabel, 2); 5400 *depthLabel = dm->depthLabel; 5401 PetscFunctionReturn(PETSC_SUCCESS); 5402 } 5403 5404 /*@ 5405 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5406 5407 Not Collective 5408 5409 Input Parameter: 5410 . dm - The `DMPLEX` object 5411 5412 Output Parameter: 5413 . depth - The number of strata (breadth first levels) in the DAG 5414 5415 Level: developer 5416 5417 Notes: 5418 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5419 5420 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5421 5422 An empty mesh gives -1. 5423 5424 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5425 @*/ 5426 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5427 { 5428 DM_Plex *mesh = (DM_Plex *)dm->data; 5429 DMLabel label; 5430 PetscInt d = -1; 5431 5432 PetscFunctionBegin; 5433 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5434 PetscAssertPointer(depth, 2); 5435 if (mesh->tr) { 5436 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5437 } else { 5438 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5439 // Allow missing depths 5440 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5441 *depth = d; 5442 } 5443 PetscFunctionReturn(PETSC_SUCCESS); 5444 } 5445 5446 /*@ 5447 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5448 5449 Not Collective 5450 5451 Input Parameters: 5452 + dm - The `DMPLEX` object 5453 - depth - The requested depth 5454 5455 Output Parameters: 5456 + start - The first point at this `depth` 5457 - end - One beyond the last point at this `depth` 5458 5459 Level: developer 5460 5461 Notes: 5462 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5463 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5464 higher dimension, e.g., "edges". 5465 5466 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5467 @*/ 5468 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PeOp PetscInt *start, PeOp PetscInt *end) 5469 { 5470 DM_Plex *mesh = (DM_Plex *)dm->data; 5471 DMLabel label; 5472 PetscInt pStart, pEnd; 5473 5474 PetscFunctionBegin; 5475 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5476 if (start) { 5477 PetscAssertPointer(start, 3); 5478 *start = 0; 5479 } 5480 if (end) { 5481 PetscAssertPointer(end, 4); 5482 *end = 0; 5483 } 5484 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5485 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5486 if (depth < 0) { 5487 if (start) *start = pStart; 5488 if (end) *end = pEnd; 5489 PetscFunctionReturn(PETSC_SUCCESS); 5490 } 5491 if (mesh->tr) { 5492 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5493 } else { 5494 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5495 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5496 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5497 } 5498 PetscFunctionReturn(PETSC_SUCCESS); 5499 } 5500 5501 /*@ 5502 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5503 5504 Not Collective 5505 5506 Input Parameters: 5507 + dm - The `DMPLEX` object 5508 - height - The requested height 5509 5510 Output Parameters: 5511 + start - The first point at this `height` 5512 - end - One beyond the last point at this `height` 5513 5514 Level: developer 5515 5516 Notes: 5517 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5518 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5519 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5520 5521 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5522 @*/ 5523 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PeOp PetscInt *start, PeOp PetscInt *end) 5524 { 5525 DMLabel label; 5526 PetscInt depth, pStart, pEnd; 5527 5528 PetscFunctionBegin; 5529 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5530 if (start) { 5531 PetscAssertPointer(start, 3); 5532 *start = 0; 5533 } 5534 if (end) { 5535 PetscAssertPointer(end, 4); 5536 *end = 0; 5537 } 5538 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5539 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5540 if (height < 0) { 5541 if (start) *start = pStart; 5542 if (end) *end = pEnd; 5543 PetscFunctionReturn(PETSC_SUCCESS); 5544 } 5545 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5546 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5547 else PetscCall(DMGetDimension(dm, &depth)); 5548 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5549 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5550 PetscFunctionReturn(PETSC_SUCCESS); 5551 } 5552 5553 /*@ 5554 DMPlexGetPointDepth - Get the `depth` of a given point 5555 5556 Not Collective 5557 5558 Input Parameters: 5559 + dm - The `DMPLEX` object 5560 - point - The point 5561 5562 Output Parameter: 5563 . depth - The depth of the `point` 5564 5565 Level: intermediate 5566 5567 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5568 @*/ 5569 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5570 { 5571 PetscFunctionBegin; 5572 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5573 PetscAssertPointer(depth, 3); 5574 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5575 PetscFunctionReturn(PETSC_SUCCESS); 5576 } 5577 5578 /*@ 5579 DMPlexGetPointHeight - Get the `height` of a given point 5580 5581 Not Collective 5582 5583 Input Parameters: 5584 + dm - The `DMPLEX` object 5585 - point - The point 5586 5587 Output Parameter: 5588 . height - The height of the `point` 5589 5590 Level: intermediate 5591 5592 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5593 @*/ 5594 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5595 { 5596 PetscInt n, pDepth; 5597 5598 PetscFunctionBegin; 5599 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5600 PetscAssertPointer(height, 3); 5601 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5602 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5603 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5604 PetscFunctionReturn(PETSC_SUCCESS); 5605 } 5606 5607 /*@ 5608 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5609 5610 Not Collective 5611 5612 Input Parameter: 5613 . dm - The `DMPLEX` object 5614 5615 Output Parameter: 5616 . celltypeLabel - The `DMLabel` recording cell polytope type 5617 5618 Level: developer 5619 5620 Note: 5621 This function will trigger automatica computation of cell types. This can be disabled by calling 5622 `DMCreateLabel`(dm, "celltype") beforehand. 5623 5624 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5625 @*/ 5626 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5627 { 5628 PetscFunctionBegin; 5629 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5630 PetscAssertPointer(celltypeLabel, 2); 5631 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5632 *celltypeLabel = dm->celltypeLabel; 5633 PetscFunctionReturn(PETSC_SUCCESS); 5634 } 5635 5636 /*@ 5637 DMPlexGetCellType - Get the polytope type of a given cell 5638 5639 Not Collective 5640 5641 Input Parameters: 5642 + dm - The `DMPLEX` object 5643 - cell - The cell 5644 5645 Output Parameter: 5646 . celltype - The polytope type of the cell 5647 5648 Level: intermediate 5649 5650 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5651 @*/ 5652 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5653 { 5654 DM_Plex *mesh = (DM_Plex *)dm->data; 5655 DMLabel label; 5656 PetscInt ct; 5657 5658 PetscFunctionBegin; 5659 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5660 PetscAssertPointer(celltype, 3); 5661 if (mesh->tr) { 5662 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5663 } else { 5664 PetscInt pStart, pEnd; 5665 5666 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5667 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5668 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5669 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5670 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5671 for (PetscInt p = pStart; p < pEnd; p++) { 5672 PetscCall(DMLabelGetValue(label, p, &ct)); 5673 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5674 } 5675 } 5676 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5677 if (PetscDefined(USE_DEBUG)) { 5678 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5679 PetscCall(DMLabelGetValue(label, cell, &ct)); 5680 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5681 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5682 } 5683 } 5684 PetscFunctionReturn(PETSC_SUCCESS); 5685 } 5686 5687 /*@ 5688 DMPlexSetCellType - Set the polytope type of a given cell 5689 5690 Not Collective 5691 5692 Input Parameters: 5693 + dm - The `DMPLEX` object 5694 . cell - The cell 5695 - celltype - The polytope type of the cell 5696 5697 Level: advanced 5698 5699 Note: 5700 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5701 is executed. This function will override the computed type. However, if automatic classification will not succeed 5702 and a user wants to manually specify all types, the classification must be disabled by calling 5703 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5704 5705 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5706 @*/ 5707 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5708 { 5709 DM_Plex *mesh = (DM_Plex *)dm->data; 5710 DMLabel label; 5711 PetscInt pStart, pEnd; 5712 5713 PetscFunctionBegin; 5714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5715 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5716 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5717 PetscCall(DMLabelSetValue(label, cell, celltype)); 5718 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5719 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5720 PetscFunctionReturn(PETSC_SUCCESS); 5721 } 5722 5723 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5724 { 5725 PetscSection section; 5726 PetscInt maxHeight; 5727 const char *prefix; 5728 5729 PetscFunctionBegin; 5730 PetscCall(DMClone(dm, cdm)); 5731 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5732 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5733 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5734 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5735 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5736 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5737 PetscCall(DMSetLocalSection(*cdm, section)); 5738 PetscCall(PetscSectionDestroy(§ion)); 5739 5740 PetscCall(DMSetNumFields(*cdm, 1)); 5741 PetscCall(DMCreateDS(*cdm)); 5742 (*cdm)->cloneOpts = PETSC_TRUE; 5743 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5744 PetscFunctionReturn(PETSC_SUCCESS); 5745 } 5746 5747 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5748 { 5749 Vec coordsLocal, cellCoordsLocal; 5750 DM coordsDM, cellCoordsDM; 5751 5752 PetscFunctionBegin; 5753 *field = NULL; 5754 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5755 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5756 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5757 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5758 if (coordsLocal && coordsDM) { 5759 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5760 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5761 } 5762 PetscFunctionReturn(PETSC_SUCCESS); 5763 } 5764 5765 /*@ 5766 DMPlexGetConeSection - Return a section which describes the layout of cone data 5767 5768 Not Collective 5769 5770 Input Parameter: 5771 . dm - The `DMPLEX` object 5772 5773 Output Parameter: 5774 . section - The `PetscSection` object 5775 5776 Level: developer 5777 5778 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5779 @*/ 5780 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5781 { 5782 DM_Plex *mesh = (DM_Plex *)dm->data; 5783 5784 PetscFunctionBegin; 5785 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5786 if (section) *section = mesh->coneSection; 5787 PetscFunctionReturn(PETSC_SUCCESS); 5788 } 5789 5790 /*@ 5791 DMPlexGetSupportSection - Return a section which describes the layout of support data 5792 5793 Not Collective 5794 5795 Input Parameter: 5796 . dm - The `DMPLEX` object 5797 5798 Output Parameter: 5799 . section - The `PetscSection` object 5800 5801 Level: developer 5802 5803 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5804 @*/ 5805 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5806 { 5807 DM_Plex *mesh = (DM_Plex *)dm->data; 5808 5809 PetscFunctionBegin; 5810 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5811 if (section) *section = mesh->supportSection; 5812 PetscFunctionReturn(PETSC_SUCCESS); 5813 } 5814 5815 /*@C 5816 DMPlexGetCones - Return cone data 5817 5818 Not Collective 5819 5820 Input Parameter: 5821 . dm - The `DMPLEX` object 5822 5823 Output Parameter: 5824 . cones - The cone for each point 5825 5826 Level: developer 5827 5828 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5829 @*/ 5830 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5831 { 5832 DM_Plex *mesh = (DM_Plex *)dm->data; 5833 5834 PetscFunctionBegin; 5835 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5836 if (cones) *cones = mesh->cones; 5837 PetscFunctionReturn(PETSC_SUCCESS); 5838 } 5839 5840 /*@C 5841 DMPlexGetConeOrientations - Return cone orientation data 5842 5843 Not Collective 5844 5845 Input Parameter: 5846 . dm - The `DMPLEX` object 5847 5848 Output Parameter: 5849 . coneOrientations - The array of cone orientations for all points 5850 5851 Level: developer 5852 5853 Notes: 5854 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5855 as returned by `DMPlexGetConeOrientation()`. 5856 5857 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5858 5859 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5860 @*/ 5861 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5862 { 5863 DM_Plex *mesh = (DM_Plex *)dm->data; 5864 5865 PetscFunctionBegin; 5866 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5867 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5868 PetscFunctionReturn(PETSC_SUCCESS); 5869 } 5870 5871 /* FEM Support */ 5872 5873 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5874 { 5875 PetscInt depth; 5876 5877 PetscFunctionBegin; 5878 PetscCall(DMPlexGetDepth(plex, &depth)); 5879 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5880 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5881 PetscFunctionReturn(PETSC_SUCCESS); 5882 } 5883 5884 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5885 { 5886 PetscInt depth; 5887 5888 PetscFunctionBegin; 5889 PetscCall(DMPlexGetDepth(plex, &depth)); 5890 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5891 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5892 PetscFunctionReturn(PETSC_SUCCESS); 5893 } 5894 5895 /* 5896 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5897 representing a line in the section. 5898 */ 5899 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5900 { 5901 PetscObject obj; 5902 PetscClassId id; 5903 PetscFE fe = NULL; 5904 5905 PetscFunctionBeginHot; 5906 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5907 PetscCall(DMGetField(dm, field, NULL, &obj)); 5908 PetscCall(PetscObjectGetClassId(obj, &id)); 5909 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5910 5911 if (!fe) { 5912 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5913 /* An order k SEM disc has k-1 dofs on an edge */ 5914 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5915 *k = *k / *Nc + 1; 5916 } else { 5917 PetscInt dual_space_size, dim; 5918 PetscDualSpace dsp; 5919 5920 PetscCall(DMGetDimension(dm, &dim)); 5921 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5922 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5923 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5924 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5925 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5926 } 5927 PetscFunctionReturn(PETSC_SUCCESS); 5928 } 5929 5930 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5931 { 5932 PetscFunctionBeginHot; 5933 if (tensor) { 5934 *dof = PetscPowInt(k + 1, dim); 5935 } else { 5936 switch (dim) { 5937 case 1: 5938 *dof = k + 1; 5939 break; 5940 case 2: 5941 *dof = ((k + 1) * (k + 2)) / 2; 5942 break; 5943 case 3: 5944 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5945 break; 5946 default: 5947 *dof = 0; 5948 } 5949 } 5950 PetscFunctionReturn(PETSC_SUCCESS); 5951 } 5952 5953 /*@ 5954 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5955 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5956 section provided (or the section of the `DM`). 5957 5958 Input Parameters: 5959 + dm - The `DM` 5960 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5961 - section - The `PetscSection` to reorder, or `NULL` for the default section 5962 5963 Example: 5964 A typical interpolated single-quad mesh might order points as 5965 .vb 5966 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5967 5968 v4 -- e6 -- v3 5969 | | 5970 e7 c0 e8 5971 | | 5972 v1 -- e5 -- v2 5973 .ve 5974 5975 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5976 dofs in the order of points, e.g., 5977 .vb 5978 c0 -> [0,1,2,3] 5979 v1 -> [4] 5980 ... 5981 e5 -> [8, 9] 5982 .ve 5983 5984 which corresponds to the dofs 5985 .vb 5986 6 10 11 7 5987 13 2 3 15 5988 12 0 1 14 5989 4 8 9 5 5990 .ve 5991 5992 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5993 .vb 5994 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5995 .ve 5996 5997 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5998 .vb 5999 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 6000 .ve 6001 6002 Level: developer 6003 6004 Notes: 6005 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 6006 degree of the basis. 6007 6008 This is required to run with libCEED. 6009 6010 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 6011 @*/ 6012 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 6013 { 6014 DMLabel label; 6015 PetscInt dim, depth = -1, eStart = -1, Nf; 6016 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 6017 6018 PetscFunctionBegin; 6019 PetscCall(DMGetDimension(dm, &dim)); 6020 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 6021 if (point < 0) { 6022 PetscInt sStart, sEnd; 6023 6024 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6025 point = sEnd - sStart ? sStart : point; 6026 } 6027 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6028 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6029 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6030 if (depth == 1) { 6031 eStart = point; 6032 } else if (depth == dim) { 6033 const PetscInt *cone; 6034 6035 PetscCall(DMPlexGetCone(dm, point, &cone)); 6036 if (dim == 2) eStart = cone[0]; 6037 else if (dim == 3) { 6038 const PetscInt *cone2; 6039 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6040 eStart = cone2[0]; 6041 } 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); 6042 } 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); 6043 6044 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6045 for (PetscInt d = 1; d <= dim; d++) { 6046 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6047 PetscInt *perm; 6048 6049 for (f = 0; f < Nf; ++f) { 6050 PetscInt dof; 6051 6052 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6053 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6054 if (!continuous && d < dim) continue; 6055 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6056 size += dof * Nc; 6057 } 6058 PetscCall(PetscMalloc1(size, &perm)); 6059 for (f = 0; f < Nf; ++f) { 6060 switch (d) { 6061 case 1: 6062 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6063 if (!continuous && d < dim) continue; 6064 /* 6065 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6066 We want [ vtx0; edge of length k-1; vtx1 ] 6067 */ 6068 if (continuous) { 6069 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6070 for (i = 0; i < k - 1; i++) 6071 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6072 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6073 foffset = offset; 6074 } else { 6075 PetscInt dof; 6076 6077 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6078 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6079 foffset = offset; 6080 } 6081 break; 6082 case 2: 6083 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6084 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6085 if (!continuous && d < dim) continue; 6086 /* The SEM order is 6087 6088 v_lb, {e_b}, v_rb, 6089 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6090 v_lt, reverse {e_t}, v_rt 6091 */ 6092 if (continuous) { 6093 const PetscInt of = 0; 6094 const PetscInt oeb = of + PetscSqr(k - 1); 6095 const PetscInt oer = oeb + (k - 1); 6096 const PetscInt oet = oer + (k - 1); 6097 const PetscInt oel = oet + (k - 1); 6098 const PetscInt ovlb = oel + (k - 1); 6099 const PetscInt ovrb = ovlb + 1; 6100 const PetscInt ovrt = ovrb + 1; 6101 const PetscInt ovlt = ovrt + 1; 6102 PetscInt o; 6103 6104 /* bottom */ 6105 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6106 for (o = oeb; o < oer; ++o) 6107 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6108 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6109 /* middle */ 6110 for (i = 0; i < k - 1; ++i) { 6111 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6112 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6113 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6114 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6115 } 6116 /* top */ 6117 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6118 for (o = oel - 1; o >= oet; --o) 6119 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6120 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6121 foffset = offset; 6122 } else { 6123 PetscInt dof; 6124 6125 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6126 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6127 foffset = offset; 6128 } 6129 break; 6130 case 3: 6131 /* The original hex closure is 6132 6133 {c, 6134 f_b, f_t, f_f, f_b, f_r, f_l, 6135 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6136 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6137 */ 6138 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6139 if (!continuous && d < dim) continue; 6140 /* The SEM order is 6141 Bottom Slice 6142 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6143 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6144 v_blb, {e_bb}, v_brb, 6145 6146 Middle Slice (j) 6147 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6148 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6149 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6150 6151 Top Slice 6152 v_tlf, {e_tf}, v_trf, 6153 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6154 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6155 */ 6156 if (continuous) { 6157 const PetscInt oc = 0; 6158 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6159 const PetscInt oft = ofb + PetscSqr(k - 1); 6160 const PetscInt off = oft + PetscSqr(k - 1); 6161 const PetscInt ofk = off + PetscSqr(k - 1); 6162 const PetscInt ofr = ofk + PetscSqr(k - 1); 6163 const PetscInt ofl = ofr + PetscSqr(k - 1); 6164 const PetscInt oebl = ofl + PetscSqr(k - 1); 6165 const PetscInt oebb = oebl + (k - 1); 6166 const PetscInt oebr = oebb + (k - 1); 6167 const PetscInt oebf = oebr + (k - 1); 6168 const PetscInt oetf = oebf + (k - 1); 6169 const PetscInt oetr = oetf + (k - 1); 6170 const PetscInt oetb = oetr + (k - 1); 6171 const PetscInt oetl = oetb + (k - 1); 6172 const PetscInt oerf = oetl + (k - 1); 6173 const PetscInt oelf = oerf + (k - 1); 6174 const PetscInt oelb = oelf + (k - 1); 6175 const PetscInt oerb = oelb + (k - 1); 6176 const PetscInt ovblf = oerb + (k - 1); 6177 const PetscInt ovblb = ovblf + 1; 6178 const PetscInt ovbrb = ovblb + 1; 6179 const PetscInt ovbrf = ovbrb + 1; 6180 const PetscInt ovtlf = ovbrf + 1; 6181 const PetscInt ovtrf = ovtlf + 1; 6182 const PetscInt ovtrb = ovtrf + 1; 6183 const PetscInt ovtlb = ovtrb + 1; 6184 PetscInt o, n; 6185 6186 /* Bottom Slice */ 6187 /* bottom */ 6188 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6189 for (o = oetf - 1; o >= oebf; --o) 6190 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6191 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6192 /* middle */ 6193 for (i = 0; i < k - 1; ++i) { 6194 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6195 for (n = 0; n < k - 1; ++n) { 6196 o = ofb + n * (k - 1) + i; 6197 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6198 } 6199 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6200 } 6201 /* top */ 6202 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6203 for (o = oebb; o < oebr; ++o) 6204 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6205 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6206 6207 /* Middle Slice */ 6208 for (j = 0; j < k - 1; ++j) { 6209 /* bottom */ 6210 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6211 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6212 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6213 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6214 /* middle */ 6215 for (i = 0; i < k - 1; ++i) { 6216 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6217 for (n = 0; n < k - 1; ++n) 6218 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6219 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6220 } 6221 /* top */ 6222 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6223 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6224 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6225 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6226 } 6227 6228 /* Top Slice */ 6229 /* bottom */ 6230 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6231 for (o = oetf; o < oetr; ++o) 6232 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6233 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6234 /* middle */ 6235 for (i = 0; i < k - 1; ++i) { 6236 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6237 for (n = 0; n < k - 1; ++n) 6238 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6239 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6240 } 6241 /* top */ 6242 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6243 for (o = oetl - 1; o >= oetb; --o) 6244 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6245 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6246 6247 foffset = offset; 6248 } else { 6249 PetscInt dof; 6250 6251 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6252 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6253 foffset = offset; 6254 } 6255 break; 6256 default: 6257 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6258 } 6259 } 6260 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6261 /* Check permutation */ 6262 { 6263 PetscInt *check; 6264 6265 PetscCall(PetscMalloc1(size, &check)); 6266 for (i = 0; i < size; ++i) { 6267 check[i] = -1; 6268 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6269 } 6270 for (i = 0; i < size; ++i) check[perm[i]] = i; 6271 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6272 PetscCall(PetscFree(check)); 6273 } 6274 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6275 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6276 PetscInt *loc_perm; 6277 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6278 for (PetscInt i = 0; i < size; i++) { 6279 loc_perm[i] = perm[i]; 6280 loc_perm[size + i] = size + perm[i]; 6281 } 6282 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6283 } 6284 } 6285 PetscFunctionReturn(PETSC_SUCCESS); 6286 } 6287 6288 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6289 { 6290 PetscDS prob; 6291 PetscInt depth, Nf, h; 6292 DMLabel label; 6293 6294 PetscFunctionBeginHot; 6295 PetscCall(DMGetDS(dm, &prob)); 6296 Nf = prob->Nf; 6297 label = dm->depthLabel; 6298 *dspace = NULL; 6299 if (field < Nf) { 6300 PetscObject disc = prob->disc[field]; 6301 6302 if (disc->classid == PETSCFE_CLASSID) { 6303 PetscDualSpace dsp; 6304 6305 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6306 PetscCall(DMLabelGetNumValues(label, &depth)); 6307 PetscCall(DMLabelGetValue(label, point, &h)); 6308 h = depth - 1 - h; 6309 if (h) { 6310 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6311 } else { 6312 *dspace = dsp; 6313 } 6314 } 6315 } 6316 PetscFunctionReturn(PETSC_SUCCESS); 6317 } 6318 6319 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6320 { 6321 PetscScalar *array; 6322 const PetscScalar *vArray; 6323 const PetscInt *cone, *coneO; 6324 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6325 6326 PetscFunctionBeginHot; 6327 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6328 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6329 PetscCall(DMPlexGetCone(dm, point, &cone)); 6330 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6331 if (!values || !*values) { 6332 if ((point >= pStart) && (point < pEnd)) { 6333 PetscInt dof; 6334 6335 PetscCall(PetscSectionGetDof(section, point, &dof)); 6336 size += dof; 6337 } 6338 for (p = 0; p < numPoints; ++p) { 6339 const PetscInt cp = cone[p]; 6340 PetscInt dof; 6341 6342 if ((cp < pStart) || (cp >= pEnd)) continue; 6343 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6344 size += dof; 6345 } 6346 if (!values) { 6347 if (csize) *csize = size; 6348 PetscFunctionReturn(PETSC_SUCCESS); 6349 } 6350 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6351 } else { 6352 array = *values; 6353 } 6354 size = 0; 6355 PetscCall(VecGetArrayRead(v, &vArray)); 6356 if ((point >= pStart) && (point < pEnd)) { 6357 PetscInt dof, off, d; 6358 const PetscScalar *varr; 6359 6360 PetscCall(PetscSectionGetDof(section, point, &dof)); 6361 PetscCall(PetscSectionGetOffset(section, point, &off)); 6362 varr = PetscSafePointerPlusOffset(vArray, off); 6363 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6364 size += dof; 6365 } 6366 for (p = 0; p < numPoints; ++p) { 6367 const PetscInt cp = cone[p]; 6368 PetscInt o = coneO[p]; 6369 PetscInt dof, off, d; 6370 const PetscScalar *varr; 6371 6372 if ((cp < pStart) || (cp >= pEnd)) continue; 6373 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6374 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6375 varr = PetscSafePointerPlusOffset(vArray, off); 6376 if (o >= 0) { 6377 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6378 } else { 6379 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6380 } 6381 size += dof; 6382 } 6383 PetscCall(VecRestoreArrayRead(v, &vArray)); 6384 if (!*values) { 6385 if (csize) *csize = size; 6386 *values = array; 6387 } else { 6388 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6389 *csize = size; 6390 } 6391 PetscFunctionReturn(PETSC_SUCCESS); 6392 } 6393 6394 /* Compress out points not in the section */ 6395 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6396 { 6397 const PetscInt np = *numPoints; 6398 PetscInt pStart, pEnd, p, q; 6399 6400 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6401 for (p = 0, q = 0; p < np; ++p) { 6402 const PetscInt r = points[p * 2]; 6403 if ((r >= pStart) && (r < pEnd)) { 6404 points[q * 2] = r; 6405 points[q * 2 + 1] = points[p * 2 + 1]; 6406 ++q; 6407 } 6408 } 6409 *numPoints = q; 6410 return PETSC_SUCCESS; 6411 } 6412 6413 /* Compressed closure does not apply closure permutation */ 6414 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6415 { 6416 const PetscInt *cla = NULL; 6417 PetscInt np, *pts = NULL; 6418 6419 PetscFunctionBeginHot; 6420 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6421 if (!ornt && *clPoints) { 6422 PetscInt dof, off; 6423 6424 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6425 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6426 PetscCall(ISGetIndices(*clPoints, &cla)); 6427 np = dof / 2; 6428 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6429 } else { 6430 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6431 PetscCall(CompressPoints_Private(section, &np, pts)); 6432 } 6433 *numPoints = np; 6434 *points = pts; 6435 *clp = cla; 6436 PetscFunctionReturn(PETSC_SUCCESS); 6437 } 6438 6439 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6440 { 6441 PetscFunctionBeginHot; 6442 if (!*clPoints) { 6443 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6444 } else { 6445 PetscCall(ISRestoreIndices(*clPoints, clp)); 6446 } 6447 *numPoints = 0; 6448 *points = NULL; 6449 *clSec = NULL; 6450 *clPoints = NULL; 6451 *clp = NULL; 6452 PetscFunctionReturn(PETSC_SUCCESS); 6453 } 6454 6455 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6456 { 6457 PetscInt offset = 0, p; 6458 const PetscInt **perms = NULL; 6459 const PetscScalar **flips = NULL; 6460 6461 PetscFunctionBeginHot; 6462 *size = 0; 6463 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6464 for (p = 0; p < numPoints; p++) { 6465 const PetscInt point = points[2 * p]; 6466 const PetscInt *perm = perms ? perms[p] : NULL; 6467 const PetscScalar *flip = flips ? flips[p] : NULL; 6468 PetscInt dof, off, d; 6469 const PetscScalar *varr; 6470 6471 PetscCall(PetscSectionGetDof(section, point, &dof)); 6472 PetscCall(PetscSectionGetOffset(section, point, &off)); 6473 varr = PetscSafePointerPlusOffset(vArray, off); 6474 if (clperm) { 6475 if (perm) { 6476 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6477 } else { 6478 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6479 } 6480 if (flip) { 6481 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6482 } 6483 } else { 6484 if (perm) { 6485 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6486 } else { 6487 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6488 } 6489 if (flip) { 6490 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6491 } 6492 } 6493 offset += dof; 6494 } 6495 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6496 *size = offset; 6497 PetscFunctionReturn(PETSC_SUCCESS); 6498 } 6499 6500 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[]) 6501 { 6502 PetscInt offset = 0, f; 6503 6504 PetscFunctionBeginHot; 6505 *size = 0; 6506 for (f = 0; f < numFields; ++f) { 6507 PetscInt p; 6508 const PetscInt **perms = NULL; 6509 const PetscScalar **flips = NULL; 6510 6511 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6512 for (p = 0; p < numPoints; p++) { 6513 const PetscInt point = points[2 * p]; 6514 PetscInt fdof, foff, b; 6515 const PetscScalar *varr; 6516 const PetscInt *perm = perms ? perms[p] : NULL; 6517 const PetscScalar *flip = flips ? flips[p] : NULL; 6518 6519 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6520 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6521 varr = &vArray[foff]; 6522 if (clperm) { 6523 if (perm) { 6524 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6525 } else { 6526 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6527 } 6528 if (flip) { 6529 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6530 } 6531 } else { 6532 if (perm) { 6533 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6534 } else { 6535 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6536 } 6537 if (flip) { 6538 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6539 } 6540 } 6541 offset += fdof; 6542 } 6543 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6544 } 6545 *size = offset; 6546 PetscFunctionReturn(PETSC_SUCCESS); 6547 } 6548 6549 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6550 { 6551 PetscSection clSection; 6552 IS clPoints; 6553 PetscInt *points = NULL; 6554 const PetscInt *clp, *perm = NULL; 6555 PetscInt depth, numFields, numPoints, asize; 6556 6557 PetscFunctionBeginHot; 6558 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6559 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6560 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6561 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6562 PetscCall(DMPlexGetDepth(dm, &depth)); 6563 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6564 if (depth == 1 && numFields < 2) { 6565 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6566 PetscFunctionReturn(PETSC_SUCCESS); 6567 } 6568 /* Get points */ 6569 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6570 /* Get sizes */ 6571 asize = 0; 6572 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6573 PetscInt dof; 6574 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6575 asize += dof; 6576 } 6577 if (values) { 6578 const PetscScalar *vArray; 6579 PetscInt size; 6580 6581 if (*values) { 6582 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); 6583 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6584 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6585 PetscCall(VecGetArrayRead(v, &vArray)); 6586 /* Get values */ 6587 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6588 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6589 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6590 /* Cleanup array */ 6591 PetscCall(VecRestoreArrayRead(v, &vArray)); 6592 } 6593 if (csize) *csize = asize; 6594 /* Cleanup points */ 6595 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6596 PetscFunctionReturn(PETSC_SUCCESS); 6597 } 6598 6599 /*@C 6600 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6601 6602 Not collective 6603 6604 Input Parameters: 6605 + dm - The `DM` 6606 . section - The section describing the layout in `v`, or `NULL` to use the default section 6607 . v - The local vector 6608 - point - The point in the `DM` 6609 6610 Input/Output Parameters: 6611 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6612 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6613 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6614 6615 Level: intermediate 6616 6617 Notes: 6618 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6619 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6620 assembly function, and a user may already have allocated storage for this operation. 6621 6622 A typical use could be 6623 .vb 6624 values = NULL; 6625 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6626 for (cl = 0; cl < clSize; ++cl) { 6627 <Compute on closure> 6628 } 6629 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6630 .ve 6631 or 6632 .vb 6633 PetscMalloc1(clMaxSize, &values); 6634 for (p = pStart; p < pEnd; ++p) { 6635 clSize = clMaxSize; 6636 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6637 for (cl = 0; cl < clSize; ++cl) { 6638 <Compute on closure> 6639 } 6640 } 6641 PetscFree(values); 6642 .ve 6643 6644 Fortran Notes: 6645 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6646 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6647 6648 `values` must be declared with 6649 .vb 6650 PetscScalar,dimension(:),pointer :: values 6651 .ve 6652 and it will be allocated internally by PETSc to hold the values returned 6653 6654 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6655 @*/ 6656 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6657 { 6658 PetscFunctionBeginHot; 6659 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6660 PetscFunctionReturn(PETSC_SUCCESS); 6661 } 6662 6663 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6664 { 6665 DMLabel depthLabel; 6666 PetscSection clSection; 6667 IS clPoints; 6668 PetscScalar *array; 6669 const PetscScalar *vArray; 6670 PetscInt *points = NULL; 6671 const PetscInt *clp, *perm = NULL; 6672 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6673 6674 PetscFunctionBeginHot; 6675 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6676 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6677 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6678 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6679 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6680 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6681 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6682 if (mdepth == 1 && numFields < 2) { 6683 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6684 PetscFunctionReturn(PETSC_SUCCESS); 6685 } 6686 /* Get points */ 6687 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6688 for (clsize = 0, p = 0; p < Np; p++) { 6689 PetscInt dof; 6690 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6691 clsize += dof; 6692 } 6693 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6694 /* Filter points */ 6695 for (p = 0; p < numPoints * 2; p += 2) { 6696 PetscInt dep; 6697 6698 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6699 if (dep != depth) continue; 6700 points[Np * 2 + 0] = points[p]; 6701 points[Np * 2 + 1] = points[p + 1]; 6702 ++Np; 6703 } 6704 /* Get array */ 6705 if (!values || !*values) { 6706 PetscInt asize = 0, dof; 6707 6708 for (p = 0; p < Np * 2; p += 2) { 6709 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6710 asize += dof; 6711 } 6712 if (!values) { 6713 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6714 if (csize) *csize = asize; 6715 PetscFunctionReturn(PETSC_SUCCESS); 6716 } 6717 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6718 } else { 6719 array = *values; 6720 } 6721 PetscCall(VecGetArrayRead(v, &vArray)); 6722 /* Get values */ 6723 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6724 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6725 /* Cleanup points */ 6726 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6727 /* Cleanup array */ 6728 PetscCall(VecRestoreArrayRead(v, &vArray)); 6729 if (!*values) { 6730 if (csize) *csize = size; 6731 *values = array; 6732 } else { 6733 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6734 *csize = size; 6735 } 6736 PetscFunctionReturn(PETSC_SUCCESS); 6737 } 6738 6739 /*@C 6740 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6741 6742 Not collective 6743 6744 Input Parameters: 6745 + dm - The `DM` 6746 . section - The section describing the layout in `v`, or `NULL` to use the default section 6747 . v - The local vector 6748 . point - The point in the `DM` 6749 . csize - The number of values in the closure, or `NULL` 6750 - values - The array of values 6751 6752 Level: intermediate 6753 6754 Note: 6755 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6756 6757 Fortran Note: 6758 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6759 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6760 6761 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6762 @*/ 6763 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6764 { 6765 PetscInt size = 0; 6766 6767 PetscFunctionBegin; 6768 /* Should work without recalculating size */ 6769 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6770 *values = NULL; 6771 PetscFunctionReturn(PETSC_SUCCESS); 6772 } 6773 6774 static inline void add(PetscScalar *x, PetscScalar y) 6775 { 6776 *x += y; 6777 } 6778 static inline void insert(PetscScalar *x, PetscScalar y) 6779 { 6780 *x = y; 6781 } 6782 6783 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[]) 6784 { 6785 PetscInt cdof; /* The number of constraints on this point */ 6786 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6787 PetscScalar *a; 6788 PetscInt off, cind = 0, k; 6789 6790 PetscFunctionBegin; 6791 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6792 PetscCall(PetscSectionGetOffset(section, point, &off)); 6793 a = &array[off]; 6794 if (!cdof || setBC) { 6795 if (clperm) { 6796 if (perm) { 6797 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6798 } else { 6799 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6800 } 6801 } else { 6802 if (perm) { 6803 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6804 } else { 6805 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6806 } 6807 } 6808 } else { 6809 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6810 if (clperm) { 6811 if (perm) { 6812 for (k = 0; k < dof; ++k) { 6813 if ((cind < cdof) && (k == cdofs[cind])) { 6814 ++cind; 6815 continue; 6816 } 6817 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6818 } 6819 } else { 6820 for (k = 0; k < dof; ++k) { 6821 if ((cind < cdof) && (k == cdofs[cind])) { 6822 ++cind; 6823 continue; 6824 } 6825 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6826 } 6827 } 6828 } else { 6829 if (perm) { 6830 for (k = 0; k < dof; ++k) { 6831 if ((cind < cdof) && (k == cdofs[cind])) { 6832 ++cind; 6833 continue; 6834 } 6835 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6836 } 6837 } else { 6838 for (k = 0; k < dof; ++k) { 6839 if ((cind < cdof) && (k == cdofs[cind])) { 6840 ++cind; 6841 continue; 6842 } 6843 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6844 } 6845 } 6846 } 6847 } 6848 PetscFunctionReturn(PETSC_SUCCESS); 6849 } 6850 6851 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[]) 6852 { 6853 PetscInt cdof; /* The number of constraints on this point */ 6854 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6855 PetscScalar *a; 6856 PetscInt off, cind = 0, k; 6857 6858 PetscFunctionBegin; 6859 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6860 PetscCall(PetscSectionGetOffset(section, point, &off)); 6861 a = &array[off]; 6862 if (cdof) { 6863 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6864 if (clperm) { 6865 if (perm) { 6866 for (k = 0; k < dof; ++k) { 6867 if ((cind < cdof) && (k == cdofs[cind])) { 6868 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6869 cind++; 6870 } 6871 } 6872 } else { 6873 for (k = 0; k < dof; ++k) { 6874 if ((cind < cdof) && (k == cdofs[cind])) { 6875 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6876 cind++; 6877 } 6878 } 6879 } 6880 } else { 6881 if (perm) { 6882 for (k = 0; k < dof; ++k) { 6883 if ((cind < cdof) && (k == cdofs[cind])) { 6884 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6885 cind++; 6886 } 6887 } 6888 } else { 6889 for (k = 0; k < dof; ++k) { 6890 if ((cind < cdof) && (k == cdofs[cind])) { 6891 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6892 cind++; 6893 } 6894 } 6895 } 6896 } 6897 } 6898 PetscFunctionReturn(PETSC_SUCCESS); 6899 } 6900 6901 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[]) 6902 { 6903 PetscScalar *a; 6904 PetscInt fdof, foff, fcdof, foffset = *offset; 6905 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6906 PetscInt cind = 0, b; 6907 6908 PetscFunctionBegin; 6909 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6910 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6911 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6912 a = &array[foff]; 6913 if (!fcdof || setBC) { 6914 if (clperm) { 6915 if (perm) { 6916 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6917 } else { 6918 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6919 } 6920 } else { 6921 if (perm) { 6922 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6923 } else { 6924 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6925 } 6926 } 6927 } else { 6928 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6929 if (clperm) { 6930 if (perm) { 6931 for (b = 0; b < fdof; b++) { 6932 if ((cind < fcdof) && (b == fcdofs[cind])) { 6933 ++cind; 6934 continue; 6935 } 6936 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6937 } 6938 } else { 6939 for (b = 0; b < fdof; b++) { 6940 if ((cind < fcdof) && (b == fcdofs[cind])) { 6941 ++cind; 6942 continue; 6943 } 6944 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6945 } 6946 } 6947 } else { 6948 if (perm) { 6949 for (b = 0; b < fdof; b++) { 6950 if ((cind < fcdof) && (b == fcdofs[cind])) { 6951 ++cind; 6952 continue; 6953 } 6954 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6955 } 6956 } else { 6957 for (b = 0; b < fdof; b++) { 6958 if ((cind < fcdof) && (b == fcdofs[cind])) { 6959 ++cind; 6960 continue; 6961 } 6962 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6963 } 6964 } 6965 } 6966 } 6967 *offset += fdof; 6968 PetscFunctionReturn(PETSC_SUCCESS); 6969 } 6970 6971 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[]) 6972 { 6973 PetscScalar *a; 6974 PetscInt fdof, foff, fcdof, foffset = *offset; 6975 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6976 PetscInt Nc, cind = 0, ncind = 0, b; 6977 PetscBool ncSet, fcSet; 6978 6979 PetscFunctionBegin; 6980 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6981 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6982 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6983 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6984 a = &array[foff]; 6985 if (fcdof) { 6986 /* We just override fcdof and fcdofs with Ncc and comps */ 6987 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6988 if (clperm) { 6989 if (perm) { 6990 if (comps) { 6991 for (b = 0; b < fdof; b++) { 6992 ncSet = fcSet = PETSC_FALSE; 6993 if (b % Nc == comps[ncind]) { 6994 ncind = (ncind + 1) % Ncc; 6995 ncSet = PETSC_TRUE; 6996 } 6997 if ((cind < fcdof) && (b == fcdofs[cind])) { 6998 ++cind; 6999 fcSet = PETSC_TRUE; 7000 } 7001 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7002 } 7003 } else { 7004 for (b = 0; b < fdof; b++) { 7005 if ((cind < fcdof) && (b == fcdofs[cind])) { 7006 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7007 ++cind; 7008 } 7009 } 7010 } 7011 } else { 7012 if (comps) { 7013 for (b = 0; b < fdof; b++) { 7014 ncSet = fcSet = PETSC_FALSE; 7015 if (b % Nc == comps[ncind]) { 7016 ncind = (ncind + 1) % Ncc; 7017 ncSet = PETSC_TRUE; 7018 } 7019 if ((cind < fcdof) && (b == fcdofs[cind])) { 7020 ++cind; 7021 fcSet = PETSC_TRUE; 7022 } 7023 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7024 } 7025 } else { 7026 for (b = 0; b < fdof; b++) { 7027 if ((cind < fcdof) && (b == fcdofs[cind])) { 7028 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7029 ++cind; 7030 } 7031 } 7032 } 7033 } 7034 } else { 7035 if (perm) { 7036 if (comps) { 7037 for (b = 0; b < fdof; b++) { 7038 ncSet = fcSet = PETSC_FALSE; 7039 if (b % Nc == comps[ncind]) { 7040 ncind = (ncind + 1) % Ncc; 7041 ncSet = PETSC_TRUE; 7042 } 7043 if ((cind < fcdof) && (b == fcdofs[cind])) { 7044 ++cind; 7045 fcSet = PETSC_TRUE; 7046 } 7047 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7048 } 7049 } else { 7050 for (b = 0; b < fdof; b++) { 7051 if ((cind < fcdof) && (b == fcdofs[cind])) { 7052 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7053 ++cind; 7054 } 7055 } 7056 } 7057 } else { 7058 if (comps) { 7059 for (b = 0; b < fdof; b++) { 7060 ncSet = fcSet = PETSC_FALSE; 7061 if (b % Nc == comps[ncind]) { 7062 ncind = (ncind + 1) % Ncc; 7063 ncSet = PETSC_TRUE; 7064 } 7065 if ((cind < fcdof) && (b == fcdofs[cind])) { 7066 ++cind; 7067 fcSet = PETSC_TRUE; 7068 } 7069 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7070 } 7071 } else { 7072 for (b = 0; b < fdof; b++) { 7073 if ((cind < fcdof) && (b == fcdofs[cind])) { 7074 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7075 ++cind; 7076 } 7077 } 7078 } 7079 } 7080 } 7081 } 7082 *offset += fdof; 7083 PetscFunctionReturn(PETSC_SUCCESS); 7084 } 7085 7086 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7087 { 7088 PetscScalar *array; 7089 const PetscInt *cone, *coneO; 7090 PetscInt pStart, pEnd, p, numPoints, off, dof; 7091 7092 PetscFunctionBeginHot; 7093 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7094 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7095 PetscCall(DMPlexGetCone(dm, point, &cone)); 7096 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7097 PetscCall(VecGetArray(v, &array)); 7098 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7099 const PetscInt cp = !p ? point : cone[p - 1]; 7100 const PetscInt o = !p ? 0 : coneO[p - 1]; 7101 7102 if ((cp < pStart) || (cp >= pEnd)) { 7103 dof = 0; 7104 continue; 7105 } 7106 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7107 /* ADD_VALUES */ 7108 { 7109 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7110 PetscScalar *a; 7111 PetscInt cdof, coff, cind = 0, k; 7112 7113 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7114 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7115 a = &array[coff]; 7116 if (!cdof) { 7117 if (o >= 0) { 7118 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7119 } else { 7120 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7121 } 7122 } else { 7123 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7124 if (o >= 0) { 7125 for (k = 0; k < dof; ++k) { 7126 if ((cind < cdof) && (k == cdofs[cind])) { 7127 ++cind; 7128 continue; 7129 } 7130 a[k] += values[off + k]; 7131 } 7132 } else { 7133 for (k = 0; k < dof; ++k) { 7134 if ((cind < cdof) && (k == cdofs[cind])) { 7135 ++cind; 7136 continue; 7137 } 7138 a[k] += values[off + dof - k - 1]; 7139 } 7140 } 7141 } 7142 } 7143 } 7144 PetscCall(VecRestoreArray(v, &array)); 7145 PetscFunctionReturn(PETSC_SUCCESS); 7146 } 7147 7148 /*@C 7149 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7150 7151 Not collective 7152 7153 Input Parameters: 7154 + dm - The `DM` 7155 . section - The section describing the layout in `v`, or `NULL` to use the default section 7156 . v - The local vector 7157 . point - The point in the `DM` 7158 . values - The array of values 7159 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7160 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7161 7162 Level: intermediate 7163 7164 Note: 7165 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7166 7167 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7168 @*/ 7169 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7170 { 7171 PetscSection clSection; 7172 IS clPoints; 7173 PetscScalar *array; 7174 PetscInt *points = NULL; 7175 const PetscInt *clp, *clperm = NULL; 7176 PetscInt depth, numFields, numPoints, p, clsize; 7177 7178 PetscFunctionBeginHot; 7179 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7180 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7181 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7182 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7183 PetscCall(DMPlexGetDepth(dm, &depth)); 7184 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7185 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7186 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7187 PetscFunctionReturn(PETSC_SUCCESS); 7188 } 7189 /* Get points */ 7190 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7191 for (clsize = 0, p = 0; p < numPoints; p++) { 7192 PetscInt dof; 7193 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7194 clsize += dof; 7195 } 7196 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7197 /* Get array */ 7198 PetscCall(VecGetArray(v, &array)); 7199 /* Get values */ 7200 if (numFields > 0) { 7201 PetscInt offset = 0, f; 7202 for (f = 0; f < numFields; ++f) { 7203 const PetscInt **perms = NULL; 7204 const PetscScalar **flips = NULL; 7205 7206 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7207 switch (mode) { 7208 case INSERT_VALUES: 7209 for (p = 0; p < numPoints; p++) { 7210 const PetscInt point = points[2 * p]; 7211 const PetscInt *perm = perms ? perms[p] : NULL; 7212 const PetscScalar *flip = flips ? flips[p] : NULL; 7213 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7214 } 7215 break; 7216 case INSERT_ALL_VALUES: 7217 for (p = 0; p < numPoints; p++) { 7218 const PetscInt point = points[2 * p]; 7219 const PetscInt *perm = perms ? perms[p] : NULL; 7220 const PetscScalar *flip = flips ? flips[p] : NULL; 7221 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7222 } 7223 break; 7224 case INSERT_BC_VALUES: 7225 for (p = 0; p < numPoints; p++) { 7226 const PetscInt point = points[2 * p]; 7227 const PetscInt *perm = perms ? perms[p] : NULL; 7228 const PetscScalar *flip = flips ? flips[p] : NULL; 7229 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7230 } 7231 break; 7232 case ADD_VALUES: 7233 for (p = 0; p < numPoints; p++) { 7234 const PetscInt point = points[2 * p]; 7235 const PetscInt *perm = perms ? perms[p] : NULL; 7236 const PetscScalar *flip = flips ? flips[p] : NULL; 7237 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7238 } 7239 break; 7240 case ADD_ALL_VALUES: 7241 for (p = 0; p < numPoints; p++) { 7242 const PetscInt point = points[2 * p]; 7243 const PetscInt *perm = perms ? perms[p] : NULL; 7244 const PetscScalar *flip = flips ? flips[p] : NULL; 7245 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7246 } 7247 break; 7248 case ADD_BC_VALUES: 7249 for (p = 0; p < numPoints; p++) { 7250 const PetscInt point = points[2 * p]; 7251 const PetscInt *perm = perms ? perms[p] : NULL; 7252 const PetscScalar *flip = flips ? flips[p] : NULL; 7253 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7254 } 7255 break; 7256 default: 7257 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7258 } 7259 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7260 } 7261 } else { 7262 PetscInt dof, off; 7263 const PetscInt **perms = NULL; 7264 const PetscScalar **flips = NULL; 7265 7266 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7267 switch (mode) { 7268 case INSERT_VALUES: 7269 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7270 const PetscInt point = points[2 * p]; 7271 const PetscInt *perm = perms ? perms[p] : NULL; 7272 const PetscScalar *flip = flips ? flips[p] : NULL; 7273 PetscCall(PetscSectionGetDof(section, point, &dof)); 7274 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7275 } 7276 break; 7277 case INSERT_ALL_VALUES: 7278 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7279 const PetscInt point = points[2 * p]; 7280 const PetscInt *perm = perms ? perms[p] : NULL; 7281 const PetscScalar *flip = flips ? flips[p] : NULL; 7282 PetscCall(PetscSectionGetDof(section, point, &dof)); 7283 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7284 } 7285 break; 7286 case INSERT_BC_VALUES: 7287 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7288 const PetscInt point = points[2 * p]; 7289 const PetscInt *perm = perms ? perms[p] : NULL; 7290 const PetscScalar *flip = flips ? flips[p] : NULL; 7291 PetscCall(PetscSectionGetDof(section, point, &dof)); 7292 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7293 } 7294 break; 7295 case ADD_VALUES: 7296 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7297 const PetscInt point = points[2 * p]; 7298 const PetscInt *perm = perms ? perms[p] : NULL; 7299 const PetscScalar *flip = flips ? flips[p] : NULL; 7300 PetscCall(PetscSectionGetDof(section, point, &dof)); 7301 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7302 } 7303 break; 7304 case ADD_ALL_VALUES: 7305 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7306 const PetscInt point = points[2 * p]; 7307 const PetscInt *perm = perms ? perms[p] : NULL; 7308 const PetscScalar *flip = flips ? flips[p] : NULL; 7309 PetscCall(PetscSectionGetDof(section, point, &dof)); 7310 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7311 } 7312 break; 7313 case ADD_BC_VALUES: 7314 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7315 const PetscInt point = points[2 * p]; 7316 const PetscInt *perm = perms ? perms[p] : NULL; 7317 const PetscScalar *flip = flips ? flips[p] : NULL; 7318 PetscCall(PetscSectionGetDof(section, point, &dof)); 7319 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7320 } 7321 break; 7322 default: 7323 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7324 } 7325 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7326 } 7327 /* Cleanup points */ 7328 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7329 /* Cleanup array */ 7330 PetscCall(VecRestoreArray(v, &array)); 7331 PetscFunctionReturn(PETSC_SUCCESS); 7332 } 7333 7334 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7335 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7336 { 7337 PetscFunctionBegin; 7338 *contains = PETSC_TRUE; 7339 if (label) { 7340 PetscInt fdof; 7341 7342 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7343 if (!*contains) { 7344 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7345 *offset += fdof; 7346 PetscFunctionReturn(PETSC_SUCCESS); 7347 } 7348 } 7349 PetscFunctionReturn(PETSC_SUCCESS); 7350 } 7351 7352 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7353 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) 7354 { 7355 PetscSection clSection; 7356 IS clPoints; 7357 PetscScalar *array; 7358 PetscInt *points = NULL; 7359 const PetscInt *clp; 7360 PetscInt numFields, numPoints, p; 7361 PetscInt offset = 0, f; 7362 7363 PetscFunctionBeginHot; 7364 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7365 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7366 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7367 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7368 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7369 /* Get points */ 7370 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7371 /* Get array */ 7372 PetscCall(VecGetArray(v, &array)); 7373 /* Get values */ 7374 for (f = 0; f < numFields; ++f) { 7375 const PetscInt **perms = NULL; 7376 const PetscScalar **flips = NULL; 7377 PetscBool contains; 7378 7379 if (!fieldActive[f]) { 7380 for (p = 0; p < numPoints * 2; p += 2) { 7381 PetscInt fdof; 7382 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7383 offset += fdof; 7384 } 7385 continue; 7386 } 7387 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7388 switch (mode) { 7389 case INSERT_VALUES: 7390 for (p = 0; p < numPoints; p++) { 7391 const PetscInt point = points[2 * p]; 7392 const PetscInt *perm = perms ? perms[p] : NULL; 7393 const PetscScalar *flip = flips ? flips[p] : NULL; 7394 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7395 if (!contains) continue; 7396 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7397 } 7398 break; 7399 case INSERT_ALL_VALUES: 7400 for (p = 0; p < numPoints; p++) { 7401 const PetscInt point = points[2 * p]; 7402 const PetscInt *perm = perms ? perms[p] : NULL; 7403 const PetscScalar *flip = flips ? flips[p] : NULL; 7404 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7405 if (!contains) continue; 7406 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7407 } 7408 break; 7409 case INSERT_BC_VALUES: 7410 for (p = 0; p < numPoints; p++) { 7411 const PetscInt point = points[2 * p]; 7412 const PetscInt *perm = perms ? perms[p] : NULL; 7413 const PetscScalar *flip = flips ? flips[p] : NULL; 7414 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7415 if (!contains) continue; 7416 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7417 } 7418 break; 7419 case ADD_VALUES: 7420 for (p = 0; p < numPoints; p++) { 7421 const PetscInt point = points[2 * p]; 7422 const PetscInt *perm = perms ? perms[p] : NULL; 7423 const PetscScalar *flip = flips ? flips[p] : NULL; 7424 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7425 if (!contains) continue; 7426 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7427 } 7428 break; 7429 case ADD_ALL_VALUES: 7430 for (p = 0; p < numPoints; p++) { 7431 const PetscInt point = points[2 * p]; 7432 const PetscInt *perm = perms ? perms[p] : NULL; 7433 const PetscScalar *flip = flips ? flips[p] : NULL; 7434 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7435 if (!contains) continue; 7436 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7437 } 7438 break; 7439 default: 7440 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7441 } 7442 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7443 } 7444 /* Cleanup points */ 7445 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7446 /* Cleanup array */ 7447 PetscCall(VecRestoreArray(v, &array)); 7448 PetscFunctionReturn(PETSC_SUCCESS); 7449 } 7450 7451 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7452 { 7453 PetscMPIInt rank; 7454 PetscInt i, j; 7455 7456 PetscFunctionBegin; 7457 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7458 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7459 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7460 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7461 numCIndices = numCIndices ? numCIndices : numRIndices; 7462 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7463 for (i = 0; i < numRIndices; i++) { 7464 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7465 for (j = 0; j < numCIndices; j++) { 7466 #if defined(PETSC_USE_COMPLEX) 7467 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7468 #else 7469 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7470 #endif 7471 } 7472 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7473 } 7474 PetscFunctionReturn(PETSC_SUCCESS); 7475 } 7476 7477 /* 7478 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7479 7480 Input Parameters: 7481 + section - The section for this data layout 7482 . islocal - Is the section (and thus indices being requested) local or global? 7483 . point - The point contributing dofs with these indices 7484 . off - The global offset of this point 7485 . loff - The local offset of each field 7486 . setBC - The flag determining whether to include indices of boundary values 7487 . perm - A permutation of the dofs on this point, or NULL 7488 - indperm - A permutation of the entire indices array, or NULL 7489 7490 Output Parameter: 7491 . indices - Indices for dofs on this point 7492 7493 Level: developer 7494 7495 Note: The indices could be local or global, depending on the value of 'off'. 7496 */ 7497 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7498 { 7499 PetscInt dof; /* The number of unknowns on this point */ 7500 PetscInt cdof; /* The number of constraints on this point */ 7501 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7502 PetscInt cind = 0, k; 7503 7504 PetscFunctionBegin; 7505 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7506 PetscCall(PetscSectionGetDof(section, point, &dof)); 7507 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7508 if (!cdof || setBC) { 7509 for (k = 0; k < dof; ++k) { 7510 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7511 const PetscInt ind = indperm ? indperm[preind] : preind; 7512 7513 indices[ind] = off + k; 7514 } 7515 } else { 7516 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7517 for (k = 0; k < dof; ++k) { 7518 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7519 const PetscInt ind = indperm ? indperm[preind] : preind; 7520 7521 if ((cind < cdof) && (k == cdofs[cind])) { 7522 /* Insert check for returning constrained indices */ 7523 indices[ind] = -(off + k + 1); 7524 ++cind; 7525 } else { 7526 indices[ind] = off + k - (islocal ? 0 : cind); 7527 } 7528 } 7529 } 7530 *loff += dof; 7531 PetscFunctionReturn(PETSC_SUCCESS); 7532 } 7533 7534 /* 7535 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7536 7537 Input Parameters: 7538 + section - a section (global or local) 7539 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7540 . point - point within section 7541 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7542 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7543 . setBC - identify constrained (boundary condition) points via involution. 7544 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7545 . permsoff - offset 7546 - indperm - index permutation 7547 7548 Output Parameter: 7549 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7550 . indices - array to hold indices (as defined by section) of each dof associated with point 7551 7552 Notes: 7553 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7554 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7555 in the local vector. 7556 7557 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7558 significant). It is invalid to call with a global section and setBC=true. 7559 7560 Developer Note: 7561 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7562 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7563 offset could be obtained from the section instead of passing it explicitly as we do now. 7564 7565 Example: 7566 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7567 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7568 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7569 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. 7570 7571 Level: developer 7572 */ 7573 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[]) 7574 { 7575 PetscInt numFields, foff, f; 7576 7577 PetscFunctionBegin; 7578 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7579 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7580 for (f = 0, foff = 0; f < numFields; ++f) { 7581 PetscInt fdof, cfdof; 7582 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7583 PetscInt cind = 0, b; 7584 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7585 7586 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7587 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7588 if (!cfdof || setBC) { 7589 for (b = 0; b < fdof; ++b) { 7590 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7591 const PetscInt ind = indperm ? indperm[preind] : preind; 7592 7593 indices[ind] = off + foff + b; 7594 } 7595 } else { 7596 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7597 for (b = 0; b < fdof; ++b) { 7598 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7599 const PetscInt ind = indperm ? indperm[preind] : preind; 7600 7601 if ((cind < cfdof) && (b == fcdofs[cind])) { 7602 indices[ind] = -(off + foff + b + 1); 7603 ++cind; 7604 } else { 7605 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7606 } 7607 } 7608 } 7609 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7610 foffs[f] += fdof; 7611 } 7612 PetscFunctionReturn(PETSC_SUCCESS); 7613 } 7614 7615 /* 7616 This version believes the globalSection offsets for each field, rather than just the point offset 7617 7618 . foffs - The offset into 'indices' for each field, since it is segregated by field 7619 7620 Notes: 7621 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7622 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7623 */ 7624 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7625 { 7626 PetscInt numFields, foff, f; 7627 7628 PetscFunctionBegin; 7629 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7630 for (f = 0; f < numFields; ++f) { 7631 PetscInt fdof, cfdof; 7632 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7633 PetscInt cind = 0, b; 7634 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7635 7636 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7637 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7638 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7639 if (!cfdof) { 7640 for (b = 0; b < fdof; ++b) { 7641 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7642 const PetscInt ind = indperm ? indperm[preind] : preind; 7643 7644 indices[ind] = foff + b; 7645 } 7646 } else { 7647 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7648 for (b = 0; b < fdof; ++b) { 7649 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7650 const PetscInt ind = indperm ? indperm[preind] : preind; 7651 7652 if ((cind < cfdof) && (b == fcdofs[cind])) { 7653 indices[ind] = -(foff + b + 1); 7654 ++cind; 7655 } else { 7656 indices[ind] = foff + b - cind; 7657 } 7658 } 7659 } 7660 foffs[f] += fdof; 7661 } 7662 PetscFunctionReturn(PETSC_SUCCESS); 7663 } 7664 7665 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7666 { 7667 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7668 7669 PetscFunctionBegin; 7670 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7671 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7672 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7673 for (PetscInt p = 0; p < nPoints; p++) { 7674 PetscInt b = pnts[2 * p]; 7675 PetscInt bSecDof = 0, bOff; 7676 PetscInt cSecDof = 0; 7677 PetscSection indices_section; 7678 7679 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7680 if (!bSecDof) continue; 7681 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7682 indices_section = cSecDof > 0 ? cSec : section; 7683 if (numFields) { 7684 PetscInt fStart[32], fEnd[32]; 7685 7686 fStart[0] = 0; 7687 fEnd[0] = 0; 7688 for (PetscInt f = 0; f < numFields; f++) { 7689 PetscInt fDof = 0; 7690 7691 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7692 fStart[f + 1] = fStart[f] + fDof; 7693 fEnd[f + 1] = fStart[f + 1]; 7694 } 7695 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7696 // only apply permutations on one side 7697 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7698 for (PetscInt f = 0; f < numFields; f++) { 7699 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7700 } 7701 } else { 7702 PetscInt bEnd = 0; 7703 7704 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7705 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7706 7707 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7708 } 7709 } 7710 PetscFunctionReturn(PETSC_SUCCESS); 7711 } 7712 7713 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[]) 7714 { 7715 Mat cMat; 7716 PetscSection aSec, cSec; 7717 IS aIS; 7718 PetscInt aStart = -1, aEnd = -1; 7719 PetscInt sStart = -1, sEnd = -1; 7720 PetscInt cStart = -1, cEnd = -1; 7721 const PetscInt *anchors; 7722 PetscInt numFields, p; 7723 PetscInt newNumPoints = 0, newNumIndices = 0; 7724 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7725 PetscInt oldOffsets[32]; 7726 PetscInt newOffsets[32]; 7727 PetscInt oldOffsetsCopy[32]; 7728 PetscInt newOffsetsCopy[32]; 7729 PetscScalar *modMat = NULL; 7730 PetscBool anyConstrained = PETSC_FALSE; 7731 7732 PetscFunctionBegin; 7733 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7734 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7735 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7736 7737 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7738 /* if there are point-to-point constraints */ 7739 if (aSec) { 7740 PetscCall(PetscArrayzero(newOffsets, 32)); 7741 PetscCall(PetscArrayzero(oldOffsets, 32)); 7742 PetscCall(ISGetIndices(aIS, &anchors)); 7743 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7744 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7745 /* figure out how many points are going to be in the new element matrix 7746 * (we allow double counting, because it's all just going to be summed 7747 * into the global matrix anyway) */ 7748 for (p = 0; p < 2 * numPoints; p += 2) { 7749 PetscInt b = points[p]; 7750 PetscInt bDof = 0, bSecDof = 0; 7751 7752 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7753 if (!bSecDof) continue; 7754 7755 for (PetscInt f = 0; f < numFields; f++) { 7756 PetscInt fDof = 0; 7757 7758 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7759 oldOffsets[f + 1] += fDof; 7760 } 7761 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7762 if (bDof) { 7763 /* this point is constrained */ 7764 /* it is going to be replaced by its anchors */ 7765 PetscInt bOff, q; 7766 7767 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7768 for (q = 0; q < bDof; q++) { 7769 PetscInt a = anchors[bOff + q]; 7770 PetscInt aDof = 0; 7771 7772 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7773 if (aDof) { 7774 anyConstrained = PETSC_TRUE; 7775 newNumPoints += 1; 7776 } 7777 newNumIndices += aDof; 7778 for (PetscInt f = 0; f < numFields; ++f) { 7779 PetscInt fDof = 0; 7780 7781 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7782 newOffsets[f + 1] += fDof; 7783 } 7784 } 7785 } else { 7786 /* this point is not constrained */ 7787 newNumPoints++; 7788 newNumIndices += bSecDof; 7789 for (PetscInt f = 0; f < numFields; ++f) { 7790 PetscInt fDof; 7791 7792 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7793 newOffsets[f + 1] += fDof; 7794 } 7795 } 7796 } 7797 } 7798 if (!anyConstrained) { 7799 if (outNumPoints) *outNumPoints = 0; 7800 if (outNumIndices) *outNumIndices = 0; 7801 if (outPoints) *outPoints = NULL; 7802 if (outMat) *outMat = NULL; 7803 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7804 PetscFunctionReturn(PETSC_SUCCESS); 7805 } 7806 7807 if (outNumPoints) *outNumPoints = newNumPoints; 7808 if (outNumIndices) *outNumIndices = newNumIndices; 7809 7810 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7811 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7812 7813 if (!outPoints && !outMat) { 7814 if (offsets) { 7815 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7816 } 7817 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7818 PetscFunctionReturn(PETSC_SUCCESS); 7819 } 7820 7821 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7822 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7823 7824 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7825 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7826 7827 /* output arrays */ 7828 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7829 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7830 7831 // get the new Points 7832 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7833 PetscInt b = points[2 * p]; 7834 PetscInt bDof = 0, bSecDof = 0, bOff; 7835 7836 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7837 if (!bSecDof) continue; 7838 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7839 if (bDof) { 7840 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7841 for (PetscInt q = 0; q < bDof; q++) { 7842 PetscInt a = anchors[bOff + q], aDof = 0; 7843 7844 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7845 if (aDof) { 7846 newPoints[2 * newP] = a; 7847 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7848 newP++; 7849 } 7850 } 7851 } else { 7852 newPoints[2 * newP] = b; 7853 newPoints[2 * newP + 1] = points[2 * p + 1]; 7854 newP++; 7855 } 7856 } 7857 7858 if (outMat) { 7859 PetscScalar *tmpMat; 7860 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7861 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7862 7863 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7864 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7865 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7866 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7867 7868 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7869 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7870 7871 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7872 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7873 7874 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7875 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7876 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7877 // for each field, insert the anchor modification into modMat 7878 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7879 PetscInt fStart = oldOffsets[f]; 7880 PetscInt fNewStart = newOffsets[f]; 7881 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7882 PetscInt b = points[2 * p]; 7883 PetscInt bDof = 0, bSecDof = 0, bOff; 7884 7885 if (b >= sStart && b < sEnd) { 7886 if (numFields) { 7887 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7888 } else { 7889 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7890 } 7891 } 7892 if (!bSecDof) continue; 7893 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7894 if (bDof) { 7895 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7896 for (PetscInt q = 0; q < bDof; q++, newP++) { 7897 PetscInt a = anchors[bOff + q], aDof = 0; 7898 7899 if (a >= sStart && a < sEnd) { 7900 if (numFields) { 7901 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7902 } else { 7903 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7904 } 7905 } 7906 if (aDof) { 7907 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7908 for (PetscInt d = 0; d < bSecDof; d++) { 7909 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7910 } 7911 } 7912 oNew += aDof; 7913 } 7914 } else { 7915 // Insert the identity matrix in this block 7916 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7917 oNew += bSecDof; 7918 newP++; 7919 } 7920 o += bSecDof; 7921 } 7922 } 7923 7924 *outMat = modMat; 7925 7926 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7927 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7928 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7929 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7930 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7931 } 7932 PetscCall(ISRestoreIndices(aIS, &anchors)); 7933 7934 /* output */ 7935 if (outPoints) { 7936 *outPoints = newPoints; 7937 } else { 7938 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7939 } 7940 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7941 PetscFunctionReturn(PETSC_SUCCESS); 7942 } 7943 7944 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) 7945 { 7946 PetscScalar *modMat = NULL; 7947 PetscInt newNumIndices = -1; 7948 7949 PetscFunctionBegin; 7950 /* 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. 7951 modMat is that matrix C */ 7952 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7953 if (outNumIndices) *outNumIndices = newNumIndices; 7954 if (modMat) { 7955 const PetscScalar *newValues = values; 7956 7957 if (multiplyRight) { 7958 PetscScalar *newNewValues = NULL; 7959 PetscBLASInt M, N, K; 7960 PetscScalar a = 1.0, b = 0.0; 7961 7962 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); 7963 7964 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7965 PetscCall(PetscBLASIntCast(numRows, &N)); 7966 PetscCall(PetscBLASIntCast(numIndices, &K)); 7967 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7968 // row-major to column-major conversion, right multiplication becomes left multiplication 7969 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7970 numCols = newNumIndices; 7971 newValues = newNewValues; 7972 } 7973 7974 if (multiplyLeft) { 7975 PetscScalar *newNewValues = NULL; 7976 PetscBLASInt M, N, K; 7977 PetscScalar a = 1.0, b = 0.0; 7978 7979 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); 7980 7981 PetscCall(PetscBLASIntCast(numCols, &M)); 7982 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7983 PetscCall(PetscBLASIntCast(numIndices, &K)); 7984 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7985 // row-major to column-major conversion, left multiplication becomes right multiplication 7986 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7987 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7988 newValues = newNewValues; 7989 } 7990 *outValues = (PetscScalar *)newValues; 7991 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7992 } 7993 PetscFunctionReturn(PETSC_SUCCESS); 7994 } 7995 7996 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) 7997 { 7998 PetscFunctionBegin; 7999 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 8000 PetscFunctionReturn(PETSC_SUCCESS); 8001 } 8002 8003 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 8004 { 8005 /* Closure ordering */ 8006 PetscSection clSection; 8007 IS clPoints; 8008 const PetscInt *clp; 8009 PetscInt *points; 8010 PetscInt Ncl, Ni = 0; 8011 8012 PetscFunctionBeginHot; 8013 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8014 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 8015 PetscInt dof; 8016 8017 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8018 Ni += dof; 8019 } 8020 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8021 *closureSize = Ni; 8022 PetscFunctionReturn(PETSC_SUCCESS); 8023 } 8024 8025 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) 8026 { 8027 /* Closure ordering */ 8028 PetscSection clSection; 8029 IS clPoints; 8030 const PetscInt *clp; 8031 PetscInt *points; 8032 const PetscInt *clperm = NULL; 8033 /* Dof permutation and sign flips */ 8034 const PetscInt **perms[32] = {NULL}; 8035 const PetscScalar **flips[32] = {NULL}; 8036 PetscScalar *valCopy = NULL; 8037 /* Hanging node constraints */ 8038 PetscInt *pointsC = NULL; 8039 PetscScalar *valuesC = NULL; 8040 PetscInt NclC, NiC; 8041 8042 PetscInt *idx; 8043 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8044 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8045 PetscInt idxStart, idxEnd; 8046 PetscInt nRows, nCols; 8047 8048 PetscFunctionBeginHot; 8049 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8050 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8051 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8052 PetscAssertPointer(numRows, 6); 8053 PetscAssertPointer(numCols, 7); 8054 if (indices) PetscAssertPointer(indices, 8); 8055 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8056 if (values) PetscAssertPointer(values, 10); 8057 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8058 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8059 PetscCall(PetscArrayzero(offsets, 32)); 8060 /* 1) Get points in closure */ 8061 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8062 if (useClPerm) { 8063 PetscInt depth, clsize; 8064 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8065 for (clsize = 0, p = 0; p < Ncl; p++) { 8066 PetscInt dof; 8067 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8068 clsize += dof; 8069 } 8070 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8071 } 8072 /* 2) Get number of indices on these points and field offsets from section */ 8073 for (p = 0; p < Ncl * 2; p += 2) { 8074 PetscInt dof, fdof; 8075 8076 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8077 for (f = 0; f < Nf; ++f) { 8078 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8079 offsets[f + 1] += fdof; 8080 } 8081 Ni += dof; 8082 } 8083 if (*numRows == -1) *numRows = Ni; 8084 if (*numCols == -1) *numCols = Ni; 8085 nRows = *numRows; 8086 nCols = *numCols; 8087 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8088 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8089 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8090 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8091 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8092 for (f = 0; f < PetscMax(1, Nf); ++f) { 8093 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8094 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8095 /* may need to apply sign changes to the element matrix */ 8096 if (values && flips[f]) { 8097 PetscInt foffset = offsets[f]; 8098 8099 for (p = 0; p < Ncl; ++p) { 8100 PetscInt pnt = points[2 * p], fdof; 8101 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8102 8103 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8104 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8105 if (flip) { 8106 PetscInt i, j, k; 8107 8108 if (!valCopy) { 8109 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8110 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8111 *values = valCopy; 8112 } 8113 for (i = 0; i < fdof; ++i) { 8114 PetscScalar fval = flip[i]; 8115 8116 if (multiplyRight) { 8117 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8118 } 8119 if (multiplyLeft) { 8120 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8121 } 8122 } 8123 } 8124 foffset += fdof; 8125 } 8126 } 8127 } 8128 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8129 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8130 if (NclC) { 8131 if (multiplyRight) *numCols = NiC; 8132 if (multiplyLeft) *numRows = NiC; 8133 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8134 for (f = 0; f < PetscMax(1, Nf); ++f) { 8135 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8136 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8137 } 8138 for (f = 0; f < PetscMax(1, Nf); ++f) { 8139 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8140 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8141 } 8142 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8143 Ncl = NclC; 8144 Ni = NiC; 8145 points = pointsC; 8146 if (values) *values = valuesC; 8147 } 8148 /* 5) Calculate indices */ 8149 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8150 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8151 if (Nf) { 8152 PetscInt idxOff; 8153 PetscBool useFieldOffsets; 8154 8155 if (outOffsets) { 8156 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8157 } 8158 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8159 if (useFieldOffsets) { 8160 for (p = 0; p < Ncl; ++p) { 8161 const PetscInt pnt = points[p * 2]; 8162 8163 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8164 } 8165 } else { 8166 for (p = 0; p < Ncl; ++p) { 8167 const PetscInt pnt = points[p * 2]; 8168 8169 if (pnt < idxStart || pnt >= idxEnd) continue; 8170 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8171 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8172 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8173 * global section. */ 8174 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8175 } 8176 } 8177 } else { 8178 PetscInt off = 0, idxOff; 8179 8180 for (p = 0; p < Ncl; ++p) { 8181 const PetscInt pnt = points[p * 2]; 8182 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8183 8184 if (pnt < idxStart || pnt >= idxEnd) continue; 8185 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8186 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8187 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8188 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8189 } 8190 } 8191 /* 6) Cleanup */ 8192 for (f = 0; f < PetscMax(1, Nf); ++f) { 8193 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8194 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8195 } 8196 if (NclC) { 8197 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8198 } else { 8199 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8200 } 8201 8202 if (indices) *indices = idx; 8203 PetscFunctionReturn(PETSC_SUCCESS); 8204 } 8205 8206 /*@C 8207 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8208 8209 Not collective 8210 8211 Input Parameters: 8212 + dm - The `DM` 8213 . section - The `PetscSection` describing the points (a local section) 8214 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8215 . point - The point defining the closure 8216 - useClPerm - Use the closure point permutation if available 8217 8218 Output Parameters: 8219 + numIndices - The number of dof indices in the closure of point with the input sections 8220 . indices - The dof indices 8221 . outOffsets - Array to write the field offsets into, or `NULL` 8222 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8223 8224 Level: advanced 8225 8226 Notes: 8227 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8228 8229 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8230 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8231 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8232 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8233 indices (with the above semantics) are implied. 8234 8235 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8236 `PetscSection`, `DMGetGlobalSection()` 8237 @*/ 8238 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8239 { 8240 PetscInt numRows = -1, numCols = -1; 8241 8242 PetscFunctionBeginHot; 8243 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8244 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8245 *numIndices = numRows; 8246 PetscFunctionReturn(PETSC_SUCCESS); 8247 } 8248 8249 /*@C 8250 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8251 8252 Not collective 8253 8254 Input Parameters: 8255 + dm - The `DM` 8256 . section - The `PetscSection` describing the points (a local section) 8257 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8258 . point - The point defining the closure 8259 - useClPerm - Use the closure point permutation if available 8260 8261 Output Parameters: 8262 + numIndices - The number of dof indices in the closure of point with the input sections 8263 . indices - The dof indices 8264 . outOffsets - Array to write the field offsets into, or `NULL` 8265 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8266 8267 Level: advanced 8268 8269 Notes: 8270 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8271 8272 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8273 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8274 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8275 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8276 indices (with the above semantics) are implied. 8277 8278 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8279 @*/ 8280 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8281 { 8282 PetscFunctionBegin; 8283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8284 PetscAssertPointer(indices, 7); 8285 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8286 PetscFunctionReturn(PETSC_SUCCESS); 8287 } 8288 8289 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8290 { 8291 DM_Plex *mesh = (DM_Plex *)dm->data; 8292 PetscInt *indices; 8293 PetscInt numIndices; 8294 const PetscScalar *valuesOrig = values; 8295 PetscErrorCode ierr; 8296 8297 PetscFunctionBegin; 8298 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8299 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8300 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8301 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8302 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8303 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8304 8305 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8306 8307 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8308 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8309 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8310 if (ierr) { 8311 PetscMPIInt rank; 8312 8313 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8314 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8315 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8316 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8317 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8318 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8319 } 8320 if (mesh->printFEM > 1) { 8321 PetscInt i; 8322 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8323 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8324 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8325 } 8326 8327 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8328 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8329 PetscFunctionReturn(PETSC_SUCCESS); 8330 } 8331 8332 /*@C 8333 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8334 8335 Not collective 8336 8337 Input Parameters: 8338 + dm - The `DM` 8339 . section - The section describing the layout in `v`, or `NULL` to use the default section 8340 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8341 . A - The matrix 8342 . point - The point in the `DM` 8343 . values - The array of values 8344 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8345 8346 Level: intermediate 8347 8348 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8349 @*/ 8350 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8351 { 8352 PetscFunctionBegin; 8353 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8354 PetscFunctionReturn(PETSC_SUCCESS); 8355 } 8356 8357 /*@C 8358 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8359 8360 Not collective 8361 8362 Input Parameters: 8363 + dmRow - The `DM` for the row fields 8364 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8365 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8366 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8367 . dmCol - The `DM` for the column fields 8368 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8369 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8370 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8371 . A - The matrix 8372 . point - The point in the `DM` 8373 . values - The array of values 8374 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8375 8376 Level: intermediate 8377 8378 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8379 @*/ 8380 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) 8381 { 8382 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8383 PetscInt *indicesRow, *indicesCol; 8384 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8385 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8386 8387 PetscErrorCode ierr; 8388 8389 PetscFunctionBegin; 8390 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8391 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8392 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8393 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8394 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8395 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8396 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8397 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8398 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8399 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8400 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8401 8402 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8403 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8404 valuesV1 = valuesV0; 8405 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8406 valuesV2 = valuesV1; 8407 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8408 8409 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8410 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8411 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8412 if (ierr) { 8413 PetscMPIInt rank; 8414 8415 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8416 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8417 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8418 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8419 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8420 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8421 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8422 } 8423 8424 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8425 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8426 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8427 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8428 PetscFunctionReturn(PETSC_SUCCESS); 8429 } 8430 8431 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8432 { 8433 DM_Plex *mesh = (DM_Plex *)dmf->data; 8434 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8435 PetscInt *cpoints = NULL; 8436 PetscInt *findices, *cindices; 8437 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8438 PetscInt foffsets[32], coffsets[32]; 8439 DMPolytopeType ct; 8440 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8441 PetscErrorCode ierr; 8442 8443 PetscFunctionBegin; 8444 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8445 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8446 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8447 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8448 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8449 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8450 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8451 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8452 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8453 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8454 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8455 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8456 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8457 PetscCall(PetscArrayzero(foffsets, 32)); 8458 PetscCall(PetscArrayzero(coffsets, 32)); 8459 /* Column indices */ 8460 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8461 maxFPoints = numCPoints; 8462 /* Compress out points not in the section */ 8463 /* TODO: Squeeze out points with 0 dof as well */ 8464 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8465 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8466 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8467 cpoints[q * 2] = cpoints[p]; 8468 cpoints[q * 2 + 1] = cpoints[p + 1]; 8469 ++q; 8470 } 8471 } 8472 numCPoints = q; 8473 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8474 PetscInt fdof; 8475 8476 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8477 if (!dof) continue; 8478 for (f = 0; f < numFields; ++f) { 8479 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8480 coffsets[f + 1] += fdof; 8481 } 8482 numCIndices += dof; 8483 } 8484 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8485 /* Row indices */ 8486 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8487 { 8488 DMPlexTransform tr; 8489 DMPolytopeType *rct; 8490 PetscInt *rsize, *rcone, *rornt, Nt; 8491 8492 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8493 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8494 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8495 numSubcells = rsize[Nt - 1]; 8496 PetscCall(DMPlexTransformDestroy(&tr)); 8497 } 8498 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8499 for (r = 0, q = 0; r < numSubcells; ++r) { 8500 /* TODO Map from coarse to fine cells */ 8501 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8502 /* Compress out points not in the section */ 8503 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8504 for (p = 0; p < numFPoints * 2; p += 2) { 8505 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8506 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8507 if (!dof) continue; 8508 for (s = 0; s < q; ++s) 8509 if (fpoints[p] == ftotpoints[s * 2]) break; 8510 if (s < q) continue; 8511 ftotpoints[q * 2] = fpoints[p]; 8512 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8513 ++q; 8514 } 8515 } 8516 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8517 } 8518 numFPoints = q; 8519 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8520 PetscInt fdof; 8521 8522 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8523 if (!dof) continue; 8524 for (f = 0; f < numFields; ++f) { 8525 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8526 foffsets[f + 1] += fdof; 8527 } 8528 numFIndices += dof; 8529 } 8530 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8531 8532 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8533 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8534 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8535 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8536 if (numFields) { 8537 const PetscInt **permsF[32] = {NULL}; 8538 const PetscInt **permsC[32] = {NULL}; 8539 8540 for (f = 0; f < numFields; f++) { 8541 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8542 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8543 } 8544 for (p = 0; p < numFPoints; p++) { 8545 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8546 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8547 } 8548 for (p = 0; p < numCPoints; p++) { 8549 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8550 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8551 } 8552 for (f = 0; f < numFields; f++) { 8553 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8554 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8555 } 8556 } else { 8557 const PetscInt **permsF = NULL; 8558 const PetscInt **permsC = NULL; 8559 8560 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8561 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8562 for (p = 0, off = 0; p < numFPoints; p++) { 8563 const PetscInt *perm = permsF ? permsF[p] : NULL; 8564 8565 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8566 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8567 } 8568 for (p = 0, off = 0; p < numCPoints; p++) { 8569 const PetscInt *perm = permsC ? permsC[p] : NULL; 8570 8571 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8572 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8573 } 8574 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8575 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8576 } 8577 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8578 /* TODO: flips */ 8579 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8580 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8581 if (ierr) { 8582 PetscMPIInt rank; 8583 8584 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8585 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8586 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8587 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8588 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8589 } 8590 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8591 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8592 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8593 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8594 PetscFunctionReturn(PETSC_SUCCESS); 8595 } 8596 8597 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8598 { 8599 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8600 PetscInt *cpoints = NULL; 8601 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8602 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8603 DMPolytopeType ct; 8604 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8605 8606 PetscFunctionBegin; 8607 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8608 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8609 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8610 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8611 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8612 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8613 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8614 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8615 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8616 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8617 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8618 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8619 /* Column indices */ 8620 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8621 maxFPoints = numCPoints; 8622 /* Compress out points not in the section */ 8623 /* TODO: Squeeze out points with 0 dof as well */ 8624 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8625 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8626 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8627 cpoints[q * 2] = cpoints[p]; 8628 cpoints[q * 2 + 1] = cpoints[p + 1]; 8629 ++q; 8630 } 8631 } 8632 numCPoints = q; 8633 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8634 PetscInt fdof; 8635 8636 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8637 if (!dof) continue; 8638 for (f = 0; f < numFields; ++f) { 8639 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8640 coffsets[f + 1] += fdof; 8641 } 8642 numCIndices += dof; 8643 } 8644 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8645 /* Row indices */ 8646 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8647 { 8648 DMPlexTransform tr; 8649 DMPolytopeType *rct; 8650 PetscInt *rsize, *rcone, *rornt, Nt; 8651 8652 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8653 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8654 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8655 numSubcells = rsize[Nt - 1]; 8656 PetscCall(DMPlexTransformDestroy(&tr)); 8657 } 8658 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8659 for (r = 0, q = 0; r < numSubcells; ++r) { 8660 /* TODO Map from coarse to fine cells */ 8661 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8662 /* Compress out points not in the section */ 8663 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8664 for (p = 0; p < numFPoints * 2; p += 2) { 8665 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8666 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8667 if (!dof) continue; 8668 for (s = 0; s < q; ++s) 8669 if (fpoints[p] == ftotpoints[s * 2]) break; 8670 if (s < q) continue; 8671 ftotpoints[q * 2] = fpoints[p]; 8672 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8673 ++q; 8674 } 8675 } 8676 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8677 } 8678 numFPoints = q; 8679 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8680 PetscInt fdof; 8681 8682 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8683 if (!dof) continue; 8684 for (f = 0; f < numFields; ++f) { 8685 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8686 foffsets[f + 1] += fdof; 8687 } 8688 numFIndices += dof; 8689 } 8690 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8691 8692 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8693 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8694 if (numFields) { 8695 const PetscInt **permsF[32] = {NULL}; 8696 const PetscInt **permsC[32] = {NULL}; 8697 8698 for (f = 0; f < numFields; f++) { 8699 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8700 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8701 } 8702 for (p = 0; p < numFPoints; p++) { 8703 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8704 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8705 } 8706 for (p = 0; p < numCPoints; p++) { 8707 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8708 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8709 } 8710 for (f = 0; f < numFields; f++) { 8711 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8712 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8713 } 8714 } else { 8715 const PetscInt **permsF = NULL; 8716 const PetscInt **permsC = NULL; 8717 8718 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8719 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8720 for (p = 0, off = 0; p < numFPoints; p++) { 8721 const PetscInt *perm = permsF ? permsF[p] : NULL; 8722 8723 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8724 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8725 } 8726 for (p = 0, off = 0; p < numCPoints; p++) { 8727 const PetscInt *perm = permsC ? permsC[p] : NULL; 8728 8729 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8730 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8731 } 8732 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8733 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8734 } 8735 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8736 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8737 PetscFunctionReturn(PETSC_SUCCESS); 8738 } 8739 8740 /*@ 8741 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8742 8743 Input Parameter: 8744 . dm - The `DMPLEX` object 8745 8746 Output Parameter: 8747 . cellHeight - The height of a cell 8748 8749 Level: developer 8750 8751 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8752 @*/ 8753 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8754 { 8755 DM_Plex *mesh = (DM_Plex *)dm->data; 8756 8757 PetscFunctionBegin; 8758 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8759 PetscAssertPointer(cellHeight, 2); 8760 *cellHeight = mesh->vtkCellHeight; 8761 PetscFunctionReturn(PETSC_SUCCESS); 8762 } 8763 8764 /*@ 8765 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8766 8767 Input Parameters: 8768 + dm - The `DMPLEX` object 8769 - cellHeight - The height of a cell 8770 8771 Level: developer 8772 8773 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8774 @*/ 8775 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8776 { 8777 DM_Plex *mesh = (DM_Plex *)dm->data; 8778 8779 PetscFunctionBegin; 8780 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8781 mesh->vtkCellHeight = cellHeight; 8782 PetscFunctionReturn(PETSC_SUCCESS); 8783 } 8784 8785 /*@ 8786 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8787 8788 Input Parameters: 8789 + dm - The `DMPLEX` object 8790 - ct - The `DMPolytopeType` of the cell 8791 8792 Output Parameters: 8793 + start - The first cell of this type, or `NULL` 8794 - end - The upper bound on this celltype, or `NULL` 8795 8796 Level: advanced 8797 8798 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8799 @*/ 8800 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end) 8801 { 8802 DM_Plex *mesh = (DM_Plex *)dm->data; 8803 DMLabel label; 8804 PetscInt pStart, pEnd; 8805 8806 PetscFunctionBegin; 8807 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8808 if (start) { 8809 PetscAssertPointer(start, 3); 8810 *start = 0; 8811 } 8812 if (end) { 8813 PetscAssertPointer(end, 4); 8814 *end = 0; 8815 } 8816 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8817 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8818 if (mesh->tr) { 8819 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8820 } else { 8821 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8822 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8823 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8824 } 8825 PetscFunctionReturn(PETSC_SUCCESS); 8826 } 8827 8828 /*@ 8829 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8830 8831 Input Parameters: 8832 + dm - The `DMPLEX` object 8833 - depth - The depth for the given point stratum 8834 8835 Output Parameter: 8836 . gsize - The global number of points in the stratum 8837 8838 Level: advanced 8839 8840 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8841 @*/ 8842 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8843 { 8844 PetscSF sf; 8845 const PetscInt *leaves; 8846 PetscInt Nl, loc, start, end, lsize = 0; 8847 8848 PetscFunctionBegin; 8849 PetscCall(DMGetPointSF(dm, &sf)); 8850 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8851 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8852 for (PetscInt p = start; p < end; ++p) { 8853 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8854 if (loc < 0) ++lsize; 8855 } 8856 PetscCallMPI(MPI_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8857 PetscFunctionReturn(PETSC_SUCCESS); 8858 } 8859 8860 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8861 { 8862 PetscSection section, globalSection; 8863 PetscInt *numbers, p; 8864 8865 PetscFunctionBegin; 8866 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8867 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8868 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8869 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8870 PetscCall(PetscSectionSetUp(section)); 8871 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8872 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8873 for (p = pStart; p < pEnd; ++p) { 8874 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8875 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8876 else numbers[p - pStart] += shift; 8877 } 8878 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8879 if (globalSize) { 8880 PetscLayout layout; 8881 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8882 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8883 PetscCall(PetscLayoutDestroy(&layout)); 8884 } 8885 PetscCall(PetscSectionDestroy(§ion)); 8886 PetscCall(PetscSectionDestroy(&globalSection)); 8887 PetscFunctionReturn(PETSC_SUCCESS); 8888 } 8889 8890 /*@ 8891 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8892 8893 Input Parameters: 8894 + dm - The `DMPLEX` object 8895 - includeAll - Whether to include all cells, or just the simplex and box cells 8896 8897 Output Parameter: 8898 . globalCellNumbers - Global cell numbers for all cells on this process 8899 8900 Level: developer 8901 8902 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8903 @*/ 8904 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8905 { 8906 PetscInt cellHeight, cStart, cEnd; 8907 8908 PetscFunctionBegin; 8909 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8910 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8911 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8912 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8913 PetscFunctionReturn(PETSC_SUCCESS); 8914 } 8915 8916 /*@ 8917 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8918 8919 Input Parameter: 8920 . dm - The `DMPLEX` object 8921 8922 Output Parameter: 8923 . globalCellNumbers - Global cell numbers for all cells on this process 8924 8925 Level: developer 8926 8927 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8928 @*/ 8929 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8930 { 8931 DM_Plex *mesh = (DM_Plex *)dm->data; 8932 8933 PetscFunctionBegin; 8934 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8935 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8936 *globalCellNumbers = mesh->globalCellNumbers; 8937 PetscFunctionReturn(PETSC_SUCCESS); 8938 } 8939 8940 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8941 { 8942 PetscInt vStart, vEnd; 8943 8944 PetscFunctionBegin; 8945 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8946 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8947 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8948 PetscFunctionReturn(PETSC_SUCCESS); 8949 } 8950 8951 /*@ 8952 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8953 8954 Input Parameter: 8955 . dm - The `DMPLEX` object 8956 8957 Output Parameter: 8958 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8959 8960 Level: developer 8961 8962 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8963 @*/ 8964 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8965 { 8966 DM_Plex *mesh = (DM_Plex *)dm->data; 8967 8968 PetscFunctionBegin; 8969 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8970 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8971 *globalVertexNumbers = mesh->globalVertexNumbers; 8972 PetscFunctionReturn(PETSC_SUCCESS); 8973 } 8974 8975 /*@ 8976 DMPlexCreatePointNumbering - Create a global numbering for all points. 8977 8978 Collective 8979 8980 Input Parameter: 8981 . dm - The `DMPLEX` object 8982 8983 Output Parameter: 8984 . globalPointNumbers - Global numbers for all points on this process 8985 8986 Level: developer 8987 8988 Notes: 8989 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8990 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8991 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8992 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8993 8994 The partitioned mesh is 8995 ``` 8996 (2)--0--(3)--1--(4) (1)--0--(2) 8997 ``` 8998 and its global numbering is 8999 ``` 9000 (3)--0--(4)--1--(5)--2--(6) 9001 ``` 9002 Then the global numbering is provided as 9003 ``` 9004 [0] Number of indices in set 5 9005 [0] 0 0 9006 [0] 1 1 9007 [0] 2 3 9008 [0] 3 4 9009 [0] 4 -6 9010 [1] Number of indices in set 3 9011 [1] 0 2 9012 [1] 1 5 9013 [1] 2 6 9014 ``` 9015 9016 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9017 @*/ 9018 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 9019 { 9020 IS nums[4]; 9021 PetscInt depths[4], gdepths[4], starts[4]; 9022 PetscInt depth, d, shift = 0; 9023 PetscBool empty = PETSC_FALSE; 9024 9025 PetscFunctionBegin; 9026 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9027 PetscCall(DMPlexGetDepth(dm, &depth)); 9028 // For unstratified meshes use dim instead of depth 9029 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9030 // If any stratum is empty, we must mark all empty 9031 for (d = 0; d <= depth; ++d) { 9032 PetscInt end; 9033 9034 depths[d] = depth - d; 9035 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9036 if (!(starts[d] - end)) empty = PETSC_TRUE; 9037 } 9038 if (empty) 9039 for (d = 0; d <= depth; ++d) { 9040 depths[d] = -1; 9041 starts[d] = -1; 9042 } 9043 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9044 PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9045 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]); 9046 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9047 for (d = 0; d <= depth; ++d) { 9048 PetscInt pStart, pEnd, gsize; 9049 9050 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9051 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9052 shift += gsize; 9053 } 9054 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9055 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9056 PetscFunctionReturn(PETSC_SUCCESS); 9057 } 9058 9059 /*@ 9060 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9061 9062 Collective 9063 9064 Input Parameter: 9065 . dm - The `DMPLEX` object 9066 9067 Output Parameter: 9068 . globalEdgeNumbers - Global numbers for all edges on this process 9069 9070 Level: developer 9071 9072 Notes: 9073 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). 9074 9075 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9076 @*/ 9077 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9078 { 9079 PetscSF sf; 9080 PetscInt eStart, eEnd; 9081 9082 PetscFunctionBegin; 9083 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9084 PetscCall(DMGetPointSF(dm, &sf)); 9085 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9086 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9087 PetscFunctionReturn(PETSC_SUCCESS); 9088 } 9089 9090 /*@ 9091 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9092 9093 Input Parameter: 9094 . dm - The `DMPLEX` object 9095 9096 Output Parameter: 9097 . ranks - The rank field 9098 9099 Options Database Key: 9100 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9101 9102 Level: intermediate 9103 9104 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9105 @*/ 9106 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9107 { 9108 DM rdm; 9109 PetscFE fe; 9110 PetscScalar *r; 9111 PetscMPIInt rank; 9112 DMPolytopeType ct; 9113 PetscInt dim, cStart, cEnd, c; 9114 PetscBool simplex; 9115 9116 PetscFunctionBeginUser; 9117 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9118 PetscAssertPointer(ranks, 2); 9119 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9120 PetscCall(DMClone(dm, &rdm)); 9121 PetscCall(DMGetDimension(rdm, &dim)); 9122 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9123 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9124 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9125 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9126 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9127 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9128 PetscCall(PetscFEDestroy(&fe)); 9129 PetscCall(DMCreateDS(rdm)); 9130 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9131 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9132 PetscCall(VecGetArray(*ranks, &r)); 9133 for (c = cStart; c < cEnd; ++c) { 9134 PetscScalar *lr; 9135 9136 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9137 if (lr) *lr = rank; 9138 } 9139 PetscCall(VecRestoreArray(*ranks, &r)); 9140 PetscCall(DMDestroy(&rdm)); 9141 PetscFunctionReturn(PETSC_SUCCESS); 9142 } 9143 9144 /*@ 9145 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9146 9147 Input Parameters: 9148 + dm - The `DMPLEX` 9149 - label - The `DMLabel` 9150 9151 Output Parameter: 9152 . val - The label value field 9153 9154 Options Database Key: 9155 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9156 9157 Level: intermediate 9158 9159 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9160 @*/ 9161 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9162 { 9163 DM rdm, plex; 9164 Vec lval; 9165 PetscSection section; 9166 PetscFE fe; 9167 PetscScalar *v; 9168 PetscInt dim, pStart, pEnd, p, cStart; 9169 DMPolytopeType ct; 9170 char name[PETSC_MAX_PATH_LEN]; 9171 const char *lname, *prefix; 9172 9173 PetscFunctionBeginUser; 9174 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9175 PetscAssertPointer(label, 2); 9176 PetscAssertPointer(val, 3); 9177 PetscCall(DMClone(dm, &rdm)); 9178 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9179 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9180 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9181 PetscCall(DMDestroy(&plex)); 9182 PetscCall(DMGetDimension(rdm, &dim)); 9183 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9184 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9185 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9186 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9187 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9188 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9189 PetscCall(PetscFEDestroy(&fe)); 9190 PetscCall(DMCreateDS(rdm)); 9191 PetscCall(DMCreateGlobalVector(rdm, val)); 9192 PetscCall(DMCreateLocalVector(rdm, &lval)); 9193 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9194 PetscCall(DMGetLocalSection(rdm, §ion)); 9195 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9196 PetscCall(VecGetArray(lval, &v)); 9197 for (p = pStart; p < pEnd; ++p) { 9198 PetscInt cval, dof, off; 9199 9200 PetscCall(PetscSectionGetDof(section, p, &dof)); 9201 if (!dof) continue; 9202 PetscCall(DMLabelGetValue(label, p, &cval)); 9203 PetscCall(PetscSectionGetOffset(section, p, &off)); 9204 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9205 } 9206 PetscCall(VecRestoreArray(lval, &v)); 9207 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9208 PetscCall(VecDestroy(&lval)); 9209 PetscCall(DMDestroy(&rdm)); 9210 PetscFunctionReturn(PETSC_SUCCESS); 9211 } 9212 9213 /*@ 9214 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9215 9216 Input Parameter: 9217 . dm - The `DMPLEX` object 9218 9219 Level: developer 9220 9221 Notes: 9222 This is a useful diagnostic when creating meshes programmatically. 9223 9224 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9225 9226 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9227 @*/ 9228 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9229 { 9230 PetscSection coneSection, supportSection; 9231 const PetscInt *cone, *support; 9232 PetscInt coneSize, c, supportSize, s; 9233 PetscInt pStart, pEnd, p, pp, csize, ssize; 9234 PetscBool storagecheck = PETSC_TRUE; 9235 9236 PetscFunctionBegin; 9237 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9238 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9239 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9240 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9241 /* Check that point p is found in the support of its cone points, and vice versa */ 9242 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9243 for (p = pStart; p < pEnd; ++p) { 9244 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9245 PetscCall(DMPlexGetCone(dm, p, &cone)); 9246 for (c = 0; c < coneSize; ++c) { 9247 PetscBool dup = PETSC_FALSE; 9248 PetscInt d; 9249 for (d = c - 1; d >= 0; --d) { 9250 if (cone[c] == cone[d]) { 9251 dup = PETSC_TRUE; 9252 break; 9253 } 9254 } 9255 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9256 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9257 for (s = 0; s < supportSize; ++s) { 9258 if (support[s] == p) break; 9259 } 9260 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9261 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9262 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9263 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9264 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9265 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9266 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9267 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]); 9268 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9269 } 9270 } 9271 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9272 if (p != pp) { 9273 storagecheck = PETSC_FALSE; 9274 continue; 9275 } 9276 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9277 PetscCall(DMPlexGetSupport(dm, p, &support)); 9278 for (s = 0; s < supportSize; ++s) { 9279 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9280 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9281 for (c = 0; c < coneSize; ++c) { 9282 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9283 if (cone[c] != pp) { 9284 c = 0; 9285 break; 9286 } 9287 if (cone[c] == p) break; 9288 } 9289 if (c >= coneSize) { 9290 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9291 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9292 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9293 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9294 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9295 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9296 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9297 } 9298 } 9299 } 9300 if (storagecheck) { 9301 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9302 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9303 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9304 } 9305 PetscFunctionReturn(PETSC_SUCCESS); 9306 } 9307 9308 /* 9309 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. 9310 */ 9311 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9312 { 9313 DMPolytopeType cct; 9314 PetscInt ptpoints[4]; 9315 const PetscInt *cone, *ccone, *ptcone; 9316 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9317 9318 PetscFunctionBegin; 9319 *unsplit = 0; 9320 switch (ct) { 9321 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9322 ptpoints[npt++] = c; 9323 break; 9324 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9325 PetscCall(DMPlexGetCone(dm, c, &cone)); 9326 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9327 for (cp = 0; cp < coneSize; ++cp) { 9328 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9329 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9330 } 9331 break; 9332 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9333 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9334 PetscCall(DMPlexGetCone(dm, c, &cone)); 9335 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9336 for (cp = 0; cp < coneSize; ++cp) { 9337 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9338 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9339 for (ccp = 0; ccp < cconeSize; ++ccp) { 9340 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9341 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9342 PetscInt p; 9343 for (p = 0; p < npt; ++p) 9344 if (ptpoints[p] == ccone[ccp]) break; 9345 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9346 } 9347 } 9348 } 9349 break; 9350 default: 9351 break; 9352 } 9353 for (pt = 0; pt < npt; ++pt) { 9354 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9355 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9356 } 9357 PetscFunctionReturn(PETSC_SUCCESS); 9358 } 9359 9360 /*@ 9361 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9362 9363 Input Parameters: 9364 + dm - The `DMPLEX` object 9365 - cellHeight - Normally 0 9366 9367 Level: developer 9368 9369 Notes: 9370 This is a useful diagnostic when creating meshes programmatically. 9371 Currently applicable only to homogeneous simplex or tensor meshes. 9372 9373 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9374 9375 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9376 @*/ 9377 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9378 { 9379 DMPlexInterpolatedFlag interp; 9380 DMPolytopeType ct; 9381 PetscInt vStart, vEnd, cStart, cEnd, c; 9382 9383 PetscFunctionBegin; 9384 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9385 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9386 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9387 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9388 for (c = cStart; c < cEnd; ++c) { 9389 PetscInt *closure = NULL; 9390 PetscInt coneSize, closureSize, cl, Nv = 0; 9391 9392 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9393 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9394 if (interp == DMPLEX_INTERPOLATED_FULL) { 9395 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9396 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)); 9397 } 9398 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9399 for (cl = 0; cl < closureSize * 2; cl += 2) { 9400 const PetscInt p = closure[cl]; 9401 if ((p >= vStart) && (p < vEnd)) ++Nv; 9402 } 9403 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9404 /* Special Case: Tensor faces with identified vertices */ 9405 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9406 PetscInt unsplit; 9407 9408 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9409 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9410 } 9411 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)); 9412 } 9413 PetscFunctionReturn(PETSC_SUCCESS); 9414 } 9415 9416 /*@ 9417 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9418 9419 Collective 9420 9421 Input Parameters: 9422 + dm - The `DMPLEX` object 9423 - cellHeight - Normally 0 9424 9425 Level: developer 9426 9427 Notes: 9428 This is a useful diagnostic when creating meshes programmatically. 9429 This routine is only relevant for meshes that are fully interpolated across all ranks. 9430 It will error out if a partially interpolated mesh is given on some rank. 9431 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9432 9433 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9434 9435 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9436 @*/ 9437 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9438 { 9439 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9440 DMPlexInterpolatedFlag interpEnum; 9441 9442 PetscFunctionBegin; 9443 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9444 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9445 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9446 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9447 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9448 PetscFunctionReturn(PETSC_SUCCESS); 9449 } 9450 9451 PetscCall(DMGetDimension(dm, &dim)); 9452 PetscCall(DMPlexGetDepth(dm, &depth)); 9453 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9454 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9455 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9456 for (c = cStart; c < cEnd; ++c) { 9457 const PetscInt *cone, *ornt, *faceSizes, *faces; 9458 const DMPolytopeType *faceTypes; 9459 DMPolytopeType ct; 9460 PetscInt numFaces, coneSize, f; 9461 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9462 9463 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9464 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9465 if (unsplit) continue; 9466 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9467 PetscCall(DMPlexGetCone(dm, c, &cone)); 9468 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9469 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9470 for (cl = 0; cl < closureSize * 2; cl += 2) { 9471 const PetscInt p = closure[cl]; 9472 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9473 } 9474 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9475 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); 9476 for (f = 0; f < numFaces; ++f) { 9477 DMPolytopeType fct; 9478 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9479 9480 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9481 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9482 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9483 const PetscInt p = fclosure[cl]; 9484 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9485 } 9486 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]); 9487 for (v = 0; v < fnumCorners; ++v) { 9488 if (fclosure[v] != faces[fOff + v]) { 9489 PetscInt v1; 9490 9491 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9492 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9493 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9494 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9495 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9496 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]); 9497 } 9498 } 9499 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9500 fOff += faceSizes[f]; 9501 } 9502 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9503 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9504 } 9505 } 9506 PetscFunctionReturn(PETSC_SUCCESS); 9507 } 9508 9509 /*@ 9510 DMPlexCheckGeometry - Check the geometry of mesh cells 9511 9512 Input Parameter: 9513 . dm - The `DMPLEX` object 9514 9515 Level: developer 9516 9517 Notes: 9518 This is a useful diagnostic when creating meshes programmatically. 9519 9520 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9521 9522 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9523 @*/ 9524 PetscErrorCode DMPlexCheckGeometry(DM dm) 9525 { 9526 Vec coordinates; 9527 PetscReal detJ, J[9], refVol = 1.0; 9528 PetscReal vol; 9529 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9530 9531 PetscFunctionBegin; 9532 PetscCall(DMGetDimension(dm, &dim)); 9533 PetscCall(DMGetCoordinateDim(dm, &dE)); 9534 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9535 PetscCall(DMPlexGetDepth(dm, &depth)); 9536 for (d = 0; d < dim; ++d) refVol *= 2.0; 9537 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9538 /* Make sure local coordinates are created, because that step is collective */ 9539 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9540 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9541 for (c = cStart; c < cEnd; ++c) { 9542 DMPolytopeType ct; 9543 PetscInt unsplit; 9544 PetscBool ignoreZeroVol = PETSC_FALSE; 9545 9546 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9547 switch (ct) { 9548 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9549 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9550 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9551 ignoreZeroVol = PETSC_TRUE; 9552 break; 9553 default: 9554 break; 9555 } 9556 switch (ct) { 9557 case DM_POLYTOPE_TRI_PRISM: 9558 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9559 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9560 case DM_POLYTOPE_PYRAMID: 9561 continue; 9562 default: 9563 break; 9564 } 9565 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9566 if (unsplit) continue; 9567 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9568 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); 9569 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9570 /* This should work with periodicity since DG coordinates should be used */ 9571 if (depth > 1) { 9572 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9573 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); 9574 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9575 } 9576 } 9577 PetscFunctionReturn(PETSC_SUCCESS); 9578 } 9579 9580 /*@ 9581 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9582 9583 Collective 9584 9585 Input Parameters: 9586 + dm - The `DMPLEX` object 9587 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9588 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9589 9590 Level: developer 9591 9592 Notes: 9593 This is mainly intended for debugging/testing purposes. 9594 9595 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9596 9597 Extra roots can come from periodic cuts, where additional points appear on the boundary 9598 9599 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9600 @*/ 9601 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9602 { 9603 PetscInt l, nleaves, nroots, overlap; 9604 const PetscInt *locals; 9605 const PetscSFNode *remotes; 9606 PetscBool distributed; 9607 MPI_Comm comm; 9608 PetscMPIInt rank; 9609 9610 PetscFunctionBegin; 9611 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9612 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9613 else pointSF = dm->sf; 9614 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9615 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9616 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9617 { 9618 PetscMPIInt mpiFlag; 9619 9620 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9621 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9622 } 9623 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9624 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9625 if (!distributed) { 9626 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); 9627 PetscFunctionReturn(PETSC_SUCCESS); 9628 } 9629 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); 9630 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9631 9632 /* Check SF graph is compatible with DMPlex chart */ 9633 { 9634 PetscInt pStart, pEnd, maxLeaf; 9635 9636 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9637 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9638 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9639 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9640 } 9641 9642 /* Check there are no cells in interface */ 9643 if (!overlap) { 9644 PetscInt cellHeight, cStart, cEnd; 9645 9646 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9647 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9648 for (l = 0; l < nleaves; ++l) { 9649 const PetscInt point = locals ? locals[l] : l; 9650 9651 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9652 } 9653 } 9654 9655 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9656 { 9657 const PetscInt *rootdegree; 9658 9659 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9660 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9661 for (l = 0; l < nleaves; ++l) { 9662 const PetscInt point = locals ? locals[l] : l; 9663 const PetscInt *cone; 9664 PetscInt coneSize, c, idx; 9665 9666 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9667 PetscCall(DMPlexGetCone(dm, point, &cone)); 9668 for (c = 0; c < coneSize; ++c) { 9669 if (!rootdegree[cone[c]]) { 9670 if (locals) { 9671 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9672 } else { 9673 idx = (cone[c] < nleaves) ? cone[c] : -1; 9674 } 9675 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9676 } 9677 } 9678 } 9679 } 9680 PetscFunctionReturn(PETSC_SUCCESS); 9681 } 9682 9683 /*@ 9684 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9685 9686 Collective 9687 9688 Input Parameter: 9689 . dm - The `DMPLEX` object 9690 9691 Level: developer 9692 9693 Notes: 9694 This is mainly intended for debugging/testing purposes. 9695 9696 Other cell types which are disconnected would be caught by the symmetry and face checks. 9697 9698 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9699 9700 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9701 @*/ 9702 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9703 { 9704 PetscInt pStart, pEnd, vStart, vEnd; 9705 9706 PetscFunctionBegin; 9707 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9708 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9709 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9710 for (PetscInt v = vStart; v < vEnd; ++v) { 9711 PetscInt suppSize; 9712 9713 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9714 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9715 } 9716 PetscFunctionReturn(PETSC_SUCCESS); 9717 } 9718 9719 /*@ 9720 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9721 9722 Input Parameter: 9723 . dm - The `DMPLEX` object 9724 9725 Level: developer 9726 9727 Notes: 9728 This is a useful diagnostic when creating meshes programmatically. 9729 9730 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9731 9732 Currently does not include `DMPlexCheckCellShape()`. 9733 9734 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9735 @*/ 9736 PetscErrorCode DMPlexCheck(DM dm) 9737 { 9738 PetscInt cellHeight; 9739 9740 PetscFunctionBegin; 9741 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9742 PetscCall(DMPlexCheckSymmetry(dm)); 9743 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9744 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9745 PetscCall(DMPlexCheckGeometry(dm)); 9746 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9747 PetscCall(DMPlexCheckInterfaceCones(dm)); 9748 PetscCall(DMPlexCheckOrphanVertices(dm)); 9749 PetscFunctionReturn(PETSC_SUCCESS); 9750 } 9751 9752 typedef struct cell_stats { 9753 PetscReal min, max, sum, squaresum; 9754 PetscInt count; 9755 } cell_stats_t; 9756 9757 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9758 { 9759 PetscInt i, N = *len; 9760 9761 for (i = 0; i < N; i++) { 9762 cell_stats_t *A = (cell_stats_t *)a; 9763 cell_stats_t *B = (cell_stats_t *)b; 9764 9765 B->min = PetscMin(A->min, B->min); 9766 B->max = PetscMax(A->max, B->max); 9767 B->sum += A->sum; 9768 B->squaresum += A->squaresum; 9769 B->count += A->count; 9770 } 9771 } 9772 9773 /*@ 9774 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9775 9776 Collective 9777 9778 Input Parameters: 9779 + dm - The `DMPLEX` object 9780 . output - If true, statistics will be displayed on `stdout` 9781 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9782 9783 Level: developer 9784 9785 Notes: 9786 This is mainly intended for debugging/testing purposes. 9787 9788 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9789 9790 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9791 @*/ 9792 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9793 { 9794 DM dmCoarse; 9795 cell_stats_t stats, globalStats; 9796 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9797 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9798 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9799 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9800 PetscMPIInt rank, size; 9801 9802 PetscFunctionBegin; 9803 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9804 stats.min = PETSC_MAX_REAL; 9805 stats.max = PETSC_MIN_REAL; 9806 stats.sum = stats.squaresum = 0.; 9807 stats.count = 0; 9808 9809 PetscCallMPI(MPI_Comm_size(comm, &size)); 9810 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9811 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9812 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9813 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9814 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9815 for (c = cStart; c < cEnd; c++) { 9816 PetscInt i; 9817 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9818 9819 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9820 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9821 for (i = 0; i < PetscSqr(cdim); ++i) { 9822 frobJ += J[i] * J[i]; 9823 frobInvJ += invJ[i] * invJ[i]; 9824 } 9825 cond2 = frobJ * frobInvJ; 9826 cond = PetscSqrtReal(cond2); 9827 9828 stats.min = PetscMin(stats.min, cond); 9829 stats.max = PetscMax(stats.max, cond); 9830 stats.sum += cond; 9831 stats.squaresum += cond2; 9832 stats.count++; 9833 if (output && cond > limit) { 9834 PetscSection coordSection; 9835 Vec coordsLocal; 9836 PetscScalar *coords = NULL; 9837 PetscInt Nv, d, clSize, cl, *closure = NULL; 9838 9839 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9840 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9841 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9842 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9843 for (i = 0; i < Nv / cdim; ++i) { 9844 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9845 for (d = 0; d < cdim; ++d) { 9846 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9847 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9848 } 9849 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9850 } 9851 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9852 for (cl = 0; cl < clSize * 2; cl += 2) { 9853 const PetscInt edge = closure[cl]; 9854 9855 if ((edge >= eStart) && (edge < eEnd)) { 9856 PetscReal len; 9857 9858 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9859 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9860 } 9861 } 9862 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9863 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9864 } 9865 } 9866 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9867 9868 if (size > 1) { 9869 PetscMPIInt blockLengths[2] = {4, 1}; 9870 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9871 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9872 MPI_Op statReduce; 9873 9874 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9875 PetscCallMPI(MPI_Type_commit(&statType)); 9876 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9877 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9878 PetscCallMPI(MPI_Op_free(&statReduce)); 9879 PetscCallMPI(MPI_Type_free(&statType)); 9880 } else { 9881 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9882 } 9883 if (rank == 0) { 9884 count = globalStats.count; 9885 min = globalStats.min; 9886 max = globalStats.max; 9887 mean = globalStats.sum / globalStats.count; 9888 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9889 } 9890 9891 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)); 9892 PetscCall(PetscFree2(J, invJ)); 9893 9894 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9895 if (dmCoarse) { 9896 PetscBool isplex; 9897 9898 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9899 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9900 } 9901 PetscFunctionReturn(PETSC_SUCCESS); 9902 } 9903 9904 /*@ 9905 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9906 orthogonal quality below given tolerance. 9907 9908 Collective 9909 9910 Input Parameters: 9911 + dm - The `DMPLEX` object 9912 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9913 - atol - [0, 1] Absolute tolerance for tagging cells. 9914 9915 Output Parameters: 9916 + OrthQual - `Vec` containing orthogonal quality per cell 9917 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9918 9919 Options Database Keys: 9920 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9921 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9922 9923 Level: intermediate 9924 9925 Notes: 9926 Orthogonal quality is given by the following formula\: 9927 9928 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9929 9930 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 9931 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9932 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9933 calculating the cosine of the angle between these vectors. 9934 9935 Orthogonal quality ranges from 1 (best) to 0 (worst). 9936 9937 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9938 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9939 9940 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9941 9942 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9943 @*/ 9944 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9945 { 9946 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9947 PetscInt *idx; 9948 PetscScalar *oqVals; 9949 const PetscScalar *cellGeomArr, *faceGeomArr; 9950 PetscReal *ci, *fi, *Ai; 9951 MPI_Comm comm; 9952 Vec cellgeom, facegeom; 9953 DM dmFace, dmCell; 9954 IS glob; 9955 ISLocalToGlobalMapping ltog; 9956 PetscViewer vwr; 9957 9958 PetscFunctionBegin; 9959 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9960 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9961 PetscAssertPointer(OrthQual, 4); 9962 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9963 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9964 PetscCall(DMGetDimension(dm, &nc)); 9965 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9966 { 9967 DMPlexInterpolatedFlag interpFlag; 9968 9969 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9970 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9971 PetscMPIInt rank; 9972 9973 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9974 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9975 } 9976 } 9977 if (OrthQualLabel) { 9978 PetscAssertPointer(OrthQualLabel, 5); 9979 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9980 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9981 } else { 9982 *OrthQualLabel = NULL; 9983 } 9984 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9985 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9986 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9987 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9988 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9989 PetscCall(VecCreate(comm, OrthQual)); 9990 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9991 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9992 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9993 PetscCall(VecSetUp(*OrthQual)); 9994 PetscCall(ISDestroy(&glob)); 9995 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9996 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9997 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9998 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9999 PetscCall(VecGetDM(cellgeom, &dmCell)); 10000 PetscCall(VecGetDM(facegeom, &dmFace)); 10001 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 10002 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 10003 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 10004 PetscInt cellarr[2], *adj = NULL; 10005 PetscScalar *cArr, *fArr; 10006 PetscReal minvalc = 1.0, minvalf = 1.0; 10007 PetscFVCellGeom *cg; 10008 10009 idx[cellIter] = cell - cStart; 10010 cellarr[0] = cell; 10011 /* Make indexing into cellGeom easier */ 10012 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10013 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10014 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10015 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10016 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10017 PetscInt i; 10018 const PetscInt neigh = adj[cellneigh]; 10019 PetscReal normci = 0, normfi = 0, normai = 0; 10020 PetscFVCellGeom *cgneigh; 10021 PetscFVFaceGeom *fg; 10022 10023 /* Don't count ourselves in the neighbor list */ 10024 if (neigh == cell) continue; 10025 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10026 cellarr[1] = neigh; 10027 { 10028 PetscInt numcovpts; 10029 const PetscInt *covpts; 10030 10031 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10032 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10033 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10034 } 10035 10036 /* Compute c_i, f_i and their norms */ 10037 for (i = 0; i < nc; i++) { 10038 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10039 fi[i] = fg->centroid[i] - cg->centroid[i]; 10040 Ai[i] = fg->normal[i]; 10041 normci += PetscPowReal(ci[i], 2); 10042 normfi += PetscPowReal(fi[i], 2); 10043 normai += PetscPowReal(Ai[i], 2); 10044 } 10045 normci = PetscSqrtReal(normci); 10046 normfi = PetscSqrtReal(normfi); 10047 normai = PetscSqrtReal(normai); 10048 10049 /* Normalize and compute for each face-cell-normal pair */ 10050 for (i = 0; i < nc; i++) { 10051 ci[i] = ci[i] / normci; 10052 fi[i] = fi[i] / normfi; 10053 Ai[i] = Ai[i] / normai; 10054 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10055 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10056 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10057 } 10058 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10059 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10060 } 10061 PetscCall(PetscFree(adj)); 10062 PetscCall(PetscFree2(cArr, fArr)); 10063 /* Defer to cell if they're equal */ 10064 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10065 if (OrthQualLabel) { 10066 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10067 } 10068 } 10069 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10070 PetscCall(VecAssemblyBegin(*OrthQual)); 10071 PetscCall(VecAssemblyEnd(*OrthQual)); 10072 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10073 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10074 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10075 if (OrthQualLabel) { 10076 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10077 } 10078 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10079 PetscCall(PetscViewerDestroy(&vwr)); 10080 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10081 PetscFunctionReturn(PETSC_SUCCESS); 10082 } 10083 10084 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10085 * interpolator construction */ 10086 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10087 { 10088 PetscSection section, newSection, gsection; 10089 PetscSF sf; 10090 PetscBool hasConstraints, ghasConstraints; 10091 10092 PetscFunctionBegin; 10093 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10094 PetscAssertPointer(odm, 2); 10095 PetscCall(DMGetLocalSection(dm, §ion)); 10096 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10097 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10098 if (!ghasConstraints) { 10099 PetscCall(PetscObjectReference((PetscObject)dm)); 10100 *odm = dm; 10101 PetscFunctionReturn(PETSC_SUCCESS); 10102 } 10103 PetscCall(DMClone(dm, odm)); 10104 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10105 PetscCall(DMGetLocalSection(*odm, &newSection)); 10106 PetscCall(DMGetPointSF(*odm, &sf)); 10107 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10108 PetscCall(DMSetGlobalSection(*odm, gsection)); 10109 PetscCall(PetscSectionDestroy(&gsection)); 10110 PetscFunctionReturn(PETSC_SUCCESS); 10111 } 10112 10113 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10114 { 10115 DM dmco, dmfo; 10116 Mat interpo; 10117 Vec rscale; 10118 Vec cglobalo, clocal; 10119 Vec fglobal, fglobalo, flocal; 10120 PetscBool regular; 10121 10122 PetscFunctionBegin; 10123 PetscCall(DMGetFullDM(dmc, &dmco)); 10124 PetscCall(DMGetFullDM(dmf, &dmfo)); 10125 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10126 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10127 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10128 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10129 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10130 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10131 PetscCall(VecSet(cglobalo, 0.)); 10132 PetscCall(VecSet(clocal, 0.)); 10133 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10134 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10135 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10136 PetscCall(VecSet(fglobal, 0.)); 10137 PetscCall(VecSet(fglobalo, 0.)); 10138 PetscCall(VecSet(flocal, 0.)); 10139 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10140 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10141 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10142 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10143 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10144 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10145 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10146 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10147 *shift = fglobal; 10148 PetscCall(VecDestroy(&flocal)); 10149 PetscCall(VecDestroy(&fglobalo)); 10150 PetscCall(VecDestroy(&clocal)); 10151 PetscCall(VecDestroy(&cglobalo)); 10152 PetscCall(VecDestroy(&rscale)); 10153 PetscCall(MatDestroy(&interpo)); 10154 PetscCall(DMDestroy(&dmfo)); 10155 PetscCall(DMDestroy(&dmco)); 10156 PetscFunctionReturn(PETSC_SUCCESS); 10157 } 10158 10159 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10160 { 10161 PetscObject shifto; 10162 Vec shift; 10163 10164 PetscFunctionBegin; 10165 if (!interp) { 10166 Vec rscale; 10167 10168 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10169 PetscCall(VecDestroy(&rscale)); 10170 } else { 10171 PetscCall(PetscObjectReference((PetscObject)interp)); 10172 } 10173 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10174 if (!shifto) { 10175 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10176 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10177 shifto = (PetscObject)shift; 10178 PetscCall(VecDestroy(&shift)); 10179 } 10180 shift = (Vec)shifto; 10181 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10182 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10183 PetscCall(MatDestroy(&interp)); 10184 PetscFunctionReturn(PETSC_SUCCESS); 10185 } 10186 10187 /* Pointwise interpolation 10188 Just code FEM for now 10189 u^f = I u^c 10190 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10191 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10192 I_{ij} = psi^f_i phi^c_j 10193 */ 10194 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10195 { 10196 PetscSection gsc, gsf; 10197 PetscInt m, n; 10198 void *ctx; 10199 DM cdm; 10200 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10201 10202 PetscFunctionBegin; 10203 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10204 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10205 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10206 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10207 10208 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10209 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10210 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10211 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10212 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10213 10214 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10215 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10216 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10217 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10218 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10219 if (scaling) { 10220 /* Use naive scaling */ 10221 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10222 } 10223 PetscFunctionReturn(PETSC_SUCCESS); 10224 } 10225 10226 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10227 { 10228 VecScatter ctx; 10229 10230 PetscFunctionBegin; 10231 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10232 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10233 PetscCall(VecScatterDestroy(&ctx)); 10234 PetscFunctionReturn(PETSC_SUCCESS); 10235 } 10236 10237 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[]) 10238 { 10239 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10240 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10241 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10242 } 10243 10244 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10245 { 10246 DM dmc; 10247 PetscDS ds; 10248 Vec ones, locmass; 10249 IS cellIS; 10250 PetscFormKey key; 10251 PetscInt depth; 10252 10253 PetscFunctionBegin; 10254 PetscCall(DMClone(dm, &dmc)); 10255 PetscCall(DMCopyDisc(dm, dmc)); 10256 PetscCall(DMGetDS(dmc, &ds)); 10257 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10258 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10259 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10260 else PetscCall(DMGetLocalVector(dm, &locmass)); 10261 PetscCall(DMGetLocalVector(dm, &ones)); 10262 PetscCall(DMPlexGetDepth(dm, &depth)); 10263 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10264 PetscCall(VecSet(locmass, 0.0)); 10265 PetscCall(VecSet(ones, 1.0)); 10266 key.label = NULL; 10267 key.value = 0; 10268 key.field = 0; 10269 key.part = 0; 10270 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10271 PetscCall(ISDestroy(&cellIS)); 10272 if (mass) { 10273 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10274 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10275 } 10276 PetscCall(DMRestoreLocalVector(dm, &ones)); 10277 if (lmass) *lmass = locmass; 10278 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10279 PetscCall(DMDestroy(&dmc)); 10280 PetscFunctionReturn(PETSC_SUCCESS); 10281 } 10282 10283 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10284 { 10285 PetscSection gsc, gsf; 10286 PetscInt m, n; 10287 void *ctx; 10288 DM cdm; 10289 PetscBool regular; 10290 10291 PetscFunctionBegin; 10292 if (dmFine == dmCoarse) { 10293 DM dmc; 10294 PetscDS ds; 10295 PetscWeakForm wf; 10296 Vec u; 10297 IS cellIS; 10298 PetscFormKey key; 10299 PetscInt depth; 10300 10301 PetscCall(DMClone(dmFine, &dmc)); 10302 PetscCall(DMCopyDisc(dmFine, dmc)); 10303 PetscCall(DMGetDS(dmc, &ds)); 10304 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10305 PetscCall(PetscWeakFormClear(wf)); 10306 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10307 PetscCall(DMCreateMatrix(dmc, mass)); 10308 PetscCall(DMGetLocalVector(dmc, &u)); 10309 PetscCall(DMPlexGetDepth(dmc, &depth)); 10310 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10311 PetscCall(MatZeroEntries(*mass)); 10312 key.label = NULL; 10313 key.value = 0; 10314 key.field = 0; 10315 key.part = 0; 10316 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10317 PetscCall(ISDestroy(&cellIS)); 10318 PetscCall(DMRestoreLocalVector(dmc, &u)); 10319 PetscCall(DMDestroy(&dmc)); 10320 } else { 10321 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10322 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10323 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10324 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10325 10326 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10327 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10328 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10329 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10330 10331 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10332 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10333 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10334 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10335 } 10336 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10337 PetscFunctionReturn(PETSC_SUCCESS); 10338 } 10339 10340 /*@ 10341 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10342 10343 Input Parameter: 10344 . dm - The `DMPLEX` object 10345 10346 Output Parameter: 10347 . regular - The flag 10348 10349 Level: intermediate 10350 10351 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10352 @*/ 10353 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10354 { 10355 PetscFunctionBegin; 10356 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10357 PetscAssertPointer(regular, 2); 10358 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10359 PetscFunctionReturn(PETSC_SUCCESS); 10360 } 10361 10362 /*@ 10363 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10364 10365 Input Parameters: 10366 + dm - The `DMPLEX` object 10367 - regular - The flag 10368 10369 Level: intermediate 10370 10371 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10372 @*/ 10373 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10374 { 10375 PetscFunctionBegin; 10376 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10377 ((DM_Plex *)dm->data)->regularRefinement = regular; 10378 PetscFunctionReturn(PETSC_SUCCESS); 10379 } 10380 10381 /*@ 10382 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10383 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10384 10385 Not Collective 10386 10387 Input Parameter: 10388 . dm - The `DMPLEX` object 10389 10390 Output Parameters: 10391 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10392 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10393 10394 Level: intermediate 10395 10396 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10397 @*/ 10398 PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS) 10399 { 10400 DM_Plex *plex = (DM_Plex *)dm->data; 10401 10402 PetscFunctionBegin; 10403 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10404 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10405 if (anchorSection) *anchorSection = plex->anchorSection; 10406 if (anchorIS) *anchorIS = plex->anchorIS; 10407 PetscFunctionReturn(PETSC_SUCCESS); 10408 } 10409 10410 /*@ 10411 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10412 10413 Collective 10414 10415 Input Parameters: 10416 + dm - The `DMPLEX` object 10417 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10418 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10419 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10420 10421 Level: intermediate 10422 10423 Notes: 10424 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10425 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10426 combination of other points' degrees of freedom. 10427 10428 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10429 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10430 10431 The reference counts of `anchorSection` and `anchorIS` are incremented. 10432 10433 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10434 @*/ 10435 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10436 { 10437 DM_Plex *plex = (DM_Plex *)dm->data; 10438 PetscMPIInt result; 10439 10440 PetscFunctionBegin; 10441 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10442 if (anchorSection) { 10443 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10444 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10445 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10446 } 10447 if (anchorIS) { 10448 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10449 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10450 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10451 } 10452 10453 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10454 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10455 plex->anchorSection = anchorSection; 10456 10457 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10458 PetscCall(ISDestroy(&plex->anchorIS)); 10459 plex->anchorIS = anchorIS; 10460 10461 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10462 PetscInt size, a, pStart, pEnd; 10463 const PetscInt *anchors; 10464 10465 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10466 PetscCall(ISGetLocalSize(anchorIS, &size)); 10467 PetscCall(ISGetIndices(anchorIS, &anchors)); 10468 for (a = 0; a < size; a++) { 10469 PetscInt p; 10470 10471 p = anchors[a]; 10472 if (p >= pStart && p < pEnd) { 10473 PetscInt dof; 10474 10475 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10476 if (dof) { 10477 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10478 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10479 } 10480 } 10481 } 10482 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10483 } 10484 /* reset the generic constraints */ 10485 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10486 PetscFunctionReturn(PETSC_SUCCESS); 10487 } 10488 10489 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10490 { 10491 PetscSection anchorSection; 10492 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10493 10494 PetscFunctionBegin; 10495 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10496 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10497 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10498 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10499 if (numFields) { 10500 PetscInt f; 10501 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10502 10503 for (f = 0; f < numFields; f++) { 10504 PetscInt numComp; 10505 10506 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10507 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10508 } 10509 } 10510 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10511 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10512 pStart = PetscMax(pStart, sStart); 10513 pEnd = PetscMin(pEnd, sEnd); 10514 pEnd = PetscMax(pStart, pEnd); 10515 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10516 for (p = pStart; p < pEnd; p++) { 10517 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10518 if (dof) { 10519 PetscCall(PetscSectionGetDof(section, p, &dof)); 10520 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10521 for (f = 0; f < numFields; f++) { 10522 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10523 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10524 } 10525 } 10526 } 10527 PetscCall(PetscSectionSetUp(*cSec)); 10528 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10529 PetscFunctionReturn(PETSC_SUCCESS); 10530 } 10531 10532 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10533 { 10534 PetscSection aSec; 10535 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10536 const PetscInt *anchors; 10537 PetscInt numFields, f; 10538 IS aIS; 10539 MatType mtype; 10540 PetscBool iscuda, iskokkos; 10541 10542 PetscFunctionBegin; 10543 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10544 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10545 PetscCall(PetscSectionGetStorageSize(section, &n)); 10546 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10547 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10548 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10549 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10550 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10551 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10552 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10553 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10554 else mtype = MATSEQAIJ; 10555 PetscCall(MatSetType(*cMat, mtype)); 10556 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10557 PetscCall(ISGetIndices(aIS, &anchors)); 10558 /* cSec will be a subset of aSec and section */ 10559 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10560 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10561 PetscCall(PetscMalloc1(m + 1, &i)); 10562 i[0] = 0; 10563 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10564 for (p = pStart; p < pEnd; p++) { 10565 PetscInt rDof, rOff, r; 10566 10567 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10568 if (!rDof) continue; 10569 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10570 if (numFields) { 10571 for (f = 0; f < numFields; f++) { 10572 annz = 0; 10573 for (r = 0; r < rDof; r++) { 10574 a = anchors[rOff + r]; 10575 if (a < sStart || a >= sEnd) continue; 10576 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10577 annz += aDof; 10578 } 10579 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10580 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10581 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10582 } 10583 } else { 10584 annz = 0; 10585 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10586 for (q = 0; q < dof; q++) { 10587 a = anchors[rOff + q]; 10588 if (a < sStart || a >= sEnd) continue; 10589 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10590 annz += aDof; 10591 } 10592 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10593 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10594 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10595 } 10596 } 10597 nnz = i[m]; 10598 PetscCall(PetscMalloc1(nnz, &j)); 10599 offset = 0; 10600 for (p = pStart; p < pEnd; p++) { 10601 if (numFields) { 10602 for (f = 0; f < numFields; f++) { 10603 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10604 for (q = 0; q < dof; q++) { 10605 PetscInt rDof, rOff, r; 10606 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10607 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10608 for (r = 0; r < rDof; r++) { 10609 PetscInt s; 10610 10611 a = anchors[rOff + r]; 10612 if (a < sStart || a >= sEnd) continue; 10613 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10614 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10615 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10616 } 10617 } 10618 } 10619 } else { 10620 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10621 for (q = 0; q < dof; q++) { 10622 PetscInt rDof, rOff, r; 10623 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10624 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10625 for (r = 0; r < rDof; r++) { 10626 PetscInt s; 10627 10628 a = anchors[rOff + r]; 10629 if (a < sStart || a >= sEnd) continue; 10630 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10631 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10632 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10633 } 10634 } 10635 } 10636 } 10637 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10638 PetscCall(PetscFree(i)); 10639 PetscCall(PetscFree(j)); 10640 PetscCall(ISRestoreIndices(aIS, &anchors)); 10641 PetscFunctionReturn(PETSC_SUCCESS); 10642 } 10643 10644 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10645 { 10646 DM_Plex *plex = (DM_Plex *)dm->data; 10647 PetscSection anchorSection, section, cSec; 10648 Mat cMat; 10649 10650 PetscFunctionBegin; 10651 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10652 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10653 if (anchorSection) { 10654 PetscInt Nf; 10655 10656 PetscCall(DMGetLocalSection(dm, §ion)); 10657 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10658 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10659 PetscCall(DMGetNumFields(dm, &Nf)); 10660 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10661 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10662 PetscCall(PetscSectionDestroy(&cSec)); 10663 PetscCall(MatDestroy(&cMat)); 10664 } 10665 PetscFunctionReturn(PETSC_SUCCESS); 10666 } 10667 10668 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10669 { 10670 IS subis; 10671 PetscSection section, subsection; 10672 10673 PetscFunctionBegin; 10674 PetscCall(DMGetLocalSection(dm, §ion)); 10675 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10676 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10677 /* Create subdomain */ 10678 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10679 /* Create submodel */ 10680 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10681 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10682 PetscCall(DMSetLocalSection(*subdm, subsection)); 10683 PetscCall(PetscSectionDestroy(&subsection)); 10684 PetscCall(DMCopyDisc(dm, *subdm)); 10685 /* Create map from submodel to global model */ 10686 if (is) { 10687 PetscSection sectionGlobal, subsectionGlobal; 10688 IS spIS; 10689 const PetscInt *spmap; 10690 PetscInt *subIndices; 10691 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10692 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10693 10694 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10695 PetscCall(ISGetIndices(spIS, &spmap)); 10696 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10697 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10698 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10699 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10700 for (p = pStart; p < pEnd; ++p) { 10701 PetscInt gdof, pSubSize = 0; 10702 10703 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10704 if (gdof > 0) { 10705 for (f = 0; f < Nf; ++f) { 10706 PetscInt fdof, fcdof; 10707 10708 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10709 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10710 pSubSize += fdof - fcdof; 10711 } 10712 subSize += pSubSize; 10713 if (pSubSize) { 10714 if (bs < 0) { 10715 bs = pSubSize; 10716 } else if (bs != pSubSize) { 10717 /* Layout does not admit a pointwise block size */ 10718 bs = 1; 10719 } 10720 } 10721 } 10722 } 10723 /* Must have same blocksize on all procs (some might have no points) */ 10724 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10725 bsLocal[1] = bs; 10726 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10727 if (bsMinMax[0] != bsMinMax[1]) { 10728 bs = 1; 10729 } else { 10730 bs = bsMinMax[0]; 10731 } 10732 PetscCall(PetscMalloc1(subSize, &subIndices)); 10733 for (p = pStart; p < pEnd; ++p) { 10734 PetscInt gdof, goff; 10735 10736 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10737 if (gdof > 0) { 10738 const PetscInt point = spmap[p]; 10739 10740 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10741 for (f = 0; f < Nf; ++f) { 10742 PetscInt fdof, fcdof, fc, f2, poff = 0; 10743 10744 /* Can get rid of this loop by storing field information in the global section */ 10745 for (f2 = 0; f2 < f; ++f2) { 10746 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10747 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10748 poff += fdof - fcdof; 10749 } 10750 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10751 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10752 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10753 } 10754 } 10755 } 10756 PetscCall(ISRestoreIndices(spIS, &spmap)); 10757 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10758 if (bs > 1) { 10759 /* We need to check that the block size does not come from non-contiguous fields */ 10760 PetscInt i, j, set = 1; 10761 for (i = 0; i < subSize; i += bs) { 10762 for (j = 0; j < bs; ++j) { 10763 if (subIndices[i + j] != subIndices[i] + j) { 10764 set = 0; 10765 break; 10766 } 10767 } 10768 } 10769 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10770 } 10771 /* Attach nullspace */ 10772 for (f = 0; f < Nf; ++f) { 10773 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10774 if ((*subdm)->nullspaceConstructors[f]) break; 10775 } 10776 if (f < Nf) { 10777 MatNullSpace nullSpace; 10778 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10779 10780 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10781 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10782 } 10783 } 10784 PetscFunctionReturn(PETSC_SUCCESS); 10785 } 10786 10787 /*@ 10788 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10789 10790 Input Parameters: 10791 + dm - The `DM` 10792 - dummy - unused argument 10793 10794 Options Database Key: 10795 . -dm_plex_monitor_throughput - Activate the monitor 10796 10797 Level: developer 10798 10799 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10800 @*/ 10801 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10802 { 10803 PetscLogHandler default_handler; 10804 10805 PetscFunctionBegin; 10806 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10807 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10808 if (default_handler) { 10809 PetscLogEvent event; 10810 PetscEventPerfInfo eventInfo; 10811 PetscLogDouble cellRate, flopRate; 10812 PetscInt cStart, cEnd, Nf, N; 10813 const char *name; 10814 10815 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10816 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10817 PetscCall(DMGetNumFields(dm, &Nf)); 10818 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10819 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10820 N = (cEnd - cStart) * Nf * eventInfo.count; 10821 flopRate = eventInfo.flops / eventInfo.time; 10822 cellRate = N / eventInfo.time; 10823 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)); 10824 } else { 10825 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."); 10826 } 10827 PetscFunctionReturn(PETSC_SUCCESS); 10828 } 10829