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_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 const char *vecname; 781 PetscInt n, nroots; 782 783 PetscCheck(dm->sfNatural, comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 784 PetscCall(VecGetLocalSize(originalv, &n)); 785 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 786 PetscCheck(n == nroots, comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 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 v = originalv; 793 } else v = originalv; 794 795 if (ishdf5) { 796 #if defined(PETSC_HAVE_HDF5) 797 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 798 #else 799 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 800 #endif 801 } else if (isvtk) { 802 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 803 } else { 804 PetscBool isseq; 805 806 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 807 if (isseq) PetscCall(VecView_Seq(v, viewer)); 808 else PetscCall(VecView_MPI(v, viewer)); 809 } 810 if (v != originalv) PetscCall(VecDestroy(&v)); 811 PetscFunctionReturn(PETSC_SUCCESS); 812 } 813 814 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 815 { 816 DM dm; 817 PetscBool ishdf5; 818 819 PetscFunctionBegin; 820 PetscCall(VecGetDM(v, &dm)); 821 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 822 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 823 if (ishdf5) { 824 DM dmBC; 825 Vec gv; 826 const char *name; 827 828 PetscCall(DMGetOutputDM(dm, &dmBC)); 829 PetscCall(DMGetGlobalVector(dmBC, &gv)); 830 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 831 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 832 PetscCall(VecLoad_Default(gv, viewer)); 833 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 834 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 835 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 836 } else PetscCall(VecLoad_Default(v, viewer)); 837 PetscFunctionReturn(PETSC_SUCCESS); 838 } 839 840 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 841 { 842 DM dm; 843 PetscBool ishdf5, isexodusii, iscgns; 844 845 PetscFunctionBegin; 846 PetscCall(VecGetDM(v, &dm)); 847 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 848 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 849 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 850 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 851 if (ishdf5) { 852 #if defined(PETSC_HAVE_HDF5) 853 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 854 #else 855 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 856 #endif 857 } else if (isexodusii) { 858 #if defined(PETSC_HAVE_EXODUSII) 859 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 860 #else 861 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 862 #endif 863 } else if (iscgns) { 864 #if defined(PETSC_HAVE_CGNS) 865 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 866 #else 867 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 868 #endif 869 } else PetscCall(VecLoad_Default(v, viewer)); 870 PetscFunctionReturn(PETSC_SUCCESS); 871 } 872 873 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 874 { 875 DM dm; 876 PetscViewerFormat format; 877 PetscBool ishdf5; 878 879 PetscFunctionBegin; 880 PetscCall(VecGetDM(originalv, &dm)); 881 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 882 PetscCall(PetscViewerGetFormat(viewer, &format)); 883 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 884 if (format == PETSC_VIEWER_NATIVE) { 885 if (dm->useNatural) { 886 if (dm->sfNatural) { 887 if (ishdf5) { 888 #if defined(PETSC_HAVE_HDF5) 889 Vec v; 890 const char *vecname; 891 892 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 893 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 894 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 895 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 896 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 897 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 898 PetscCall(VecDestroy(&v)); 899 #else 900 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 901 #endif 902 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 903 } 904 } else PetscCall(VecLoad_Default(originalv, viewer)); 905 } 906 PetscFunctionReturn(PETSC_SUCCESS); 907 } 908 909 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 910 { 911 PetscSection coordSection; 912 Vec coordinates; 913 DMLabel depthLabel, celltypeLabel; 914 const char *name[4]; 915 const PetscScalar *a; 916 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 917 918 PetscFunctionBegin; 919 PetscCall(DMGetDimension(dm, &dim)); 920 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 921 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 922 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 923 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 924 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 925 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 926 PetscCall(VecGetArrayRead(coordinates, &a)); 927 name[0] = "vertex"; 928 name[1] = "edge"; 929 name[dim - 1] = "face"; 930 name[dim] = "cell"; 931 for (c = cStart; c < cEnd; ++c) { 932 PetscInt *closure = NULL; 933 PetscInt closureSize, cl, ct; 934 935 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 936 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 937 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 938 PetscCall(PetscViewerASCIIPushTab(viewer)); 939 for (cl = 0; cl < closureSize * 2; cl += 2) { 940 PetscInt point = closure[cl], depth, dof, off, d, p; 941 942 if ((point < pStart) || (point >= pEnd)) continue; 943 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 944 if (!dof) continue; 945 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 946 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 947 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 948 for (p = 0; p < dof / dim; ++p) { 949 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 950 for (d = 0; d < dim; ++d) { 951 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 952 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 953 } 954 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 955 } 956 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 957 } 958 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 959 PetscCall(PetscViewerASCIIPopTab(viewer)); 960 } 961 PetscCall(VecRestoreArrayRead(coordinates, &a)); 962 PetscFunctionReturn(PETSC_SUCCESS); 963 } 964 965 typedef enum { 966 CS_CARTESIAN, 967 CS_POLAR, 968 CS_CYLINDRICAL, 969 CS_SPHERICAL 970 } CoordSystem; 971 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 972 973 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 974 { 975 PetscInt i; 976 977 PetscFunctionBegin; 978 if (dim > 3) { 979 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 980 } else { 981 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 982 983 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 984 switch (cs) { 985 case CS_CARTESIAN: 986 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 987 break; 988 case CS_POLAR: 989 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 990 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 991 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 992 break; 993 case CS_CYLINDRICAL: 994 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 995 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 996 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 997 trcoords[2] = coords[2]; 998 break; 999 case CS_SPHERICAL: 1000 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 1001 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 1002 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 1003 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 1004 break; 1005 } 1006 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 1007 } 1008 PetscFunctionReturn(PETSC_SUCCESS); 1009 } 1010 1011 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 1012 { 1013 DM_Plex *mesh = (DM_Plex *)dm->data; 1014 DM cdm, cdmCell; 1015 PetscSection coordSection, coordSectionCell; 1016 Vec coordinates, coordinatesCell; 1017 PetscViewerFormat format; 1018 1019 PetscFunctionBegin; 1020 PetscCall(PetscViewerGetFormat(viewer, &format)); 1021 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1022 const char *name; 1023 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1024 PetscInt pStart, pEnd, p, numLabels, l; 1025 PetscMPIInt rank, size; 1026 1027 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1028 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1029 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1030 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1031 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1032 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1033 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1034 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1035 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1036 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1037 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1038 PetscCall(DMGetDimension(dm, &dim)); 1039 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1040 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1041 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1042 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1043 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1044 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1045 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1046 for (p = pStart; p < pEnd; ++p) { 1047 PetscInt dof, off, s; 1048 1049 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1050 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1051 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1052 } 1053 PetscCall(PetscViewerFlush(viewer)); 1054 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1055 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1056 for (p = pStart; p < pEnd; ++p) { 1057 PetscInt dof, off, c; 1058 1059 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1060 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1061 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])); 1062 } 1063 PetscCall(PetscViewerFlush(viewer)); 1064 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1065 if (coordSection && coordinates) { 1066 CoordSystem cs = CS_CARTESIAN; 1067 const PetscScalar *array, *arrayCell = NULL; 1068 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1069 PetscMPIInt rank; 1070 const char *name; 1071 1072 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1073 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1074 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1075 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1076 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1077 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1078 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1079 pStart = PetscMin(pvStart, pcStart); 1080 pEnd = PetscMax(pvEnd, pcEnd); 1081 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1082 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1083 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1084 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1085 1086 PetscCall(VecGetArrayRead(coordinates, &array)); 1087 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1088 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1089 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1090 for (p = pStart; p < pEnd; ++p) { 1091 PetscInt dof, off; 1092 1093 if (p >= pvStart && p < pvEnd) { 1094 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1095 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1096 if (dof) { 1097 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1098 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1099 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1100 } 1101 } 1102 if (cdmCell && p >= pcStart && p < pcEnd) { 1103 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1104 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1105 if (dof) { 1106 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1107 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1108 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1109 } 1110 } 1111 } 1112 PetscCall(PetscViewerFlush(viewer)); 1113 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1114 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1115 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1116 } 1117 PetscCall(DMGetNumLabels(dm, &numLabels)); 1118 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1119 for (l = 0; l < numLabels; ++l) { 1120 DMLabel label; 1121 PetscBool isdepth; 1122 const char *name; 1123 1124 PetscCall(DMGetLabelName(dm, l, &name)); 1125 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1126 if (isdepth) continue; 1127 PetscCall(DMGetLabel(dm, name, &label)); 1128 PetscCall(DMLabelView(label, viewer)); 1129 } 1130 if (size > 1) { 1131 PetscSF sf; 1132 1133 PetscCall(DMGetPointSF(dm, &sf)); 1134 PetscCall(PetscSFView(sf, viewer)); 1135 } 1136 if (mesh->periodic.face_sfs) 1137 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1138 PetscCall(PetscViewerFlush(viewer)); 1139 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1140 const char *name, *color; 1141 const char *defcolors[3] = {"gray", "orange", "green"}; 1142 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1143 char lname[PETSC_MAX_PATH_LEN]; 1144 PetscReal scale = 2.0; 1145 PetscReal tikzscale = 1.0; 1146 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1147 double tcoords[3]; 1148 PetscScalar *coords; 1149 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; 1150 PetscMPIInt rank, size; 1151 char **names, **colors, **lcolors; 1152 PetscBool flg, lflg; 1153 PetscBT wp = NULL; 1154 PetscInt pEnd, pStart; 1155 1156 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1157 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1158 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1159 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1160 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1161 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1162 PetscCall(DMGetDimension(dm, &dim)); 1163 PetscCall(DMPlexGetDepth(dm, &depth)); 1164 PetscCall(DMGetNumLabels(dm, &numLabels)); 1165 numLabels = PetscMax(numLabels, 10); 1166 numColors = 10; 1167 numLColors = 10; 1168 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1169 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1170 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1171 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1172 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1173 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1174 n = 4; 1175 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1176 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1177 n = 4; 1178 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1179 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1180 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1181 if (!useLabels) numLabels = 0; 1182 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1183 if (!useColors) { 1184 numColors = 3; 1185 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1186 } 1187 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1188 if (!useColors) { 1189 numLColors = 4; 1190 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1191 } 1192 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1193 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1194 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1195 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1196 if (depth < dim) plotEdges = PETSC_FALSE; 1197 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1198 1199 /* filter points with labelvalue != labeldefaultvalue */ 1200 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1201 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1202 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1203 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1204 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1205 if (lflg) { 1206 DMLabel lbl; 1207 1208 PetscCall(DMGetLabel(dm, lname, &lbl)); 1209 if (lbl) { 1210 PetscInt val, defval; 1211 1212 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1213 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1214 for (c = pStart; c < pEnd; c++) { 1215 PetscInt *closure = NULL; 1216 PetscInt closureSize; 1217 1218 PetscCall(DMLabelGetValue(lbl, c, &val)); 1219 if (val == defval) continue; 1220 1221 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1222 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1223 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1224 } 1225 } 1226 } 1227 1228 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1229 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1230 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1231 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1232 \\documentclass[tikz]{standalone}\n\n\ 1233 \\usepackage{pgflibraryshapes}\n\ 1234 \\usetikzlibrary{backgrounds}\n\ 1235 \\usetikzlibrary{arrows}\n\ 1236 \\begin{document}\n")); 1237 if (size > 1) { 1238 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1239 for (p = 0; p < size; ++p) { 1240 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1241 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1242 } 1243 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1244 } 1245 if (drawHasse) { 1246 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1247 1248 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1249 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1258 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1264 } 1265 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1266 1267 /* Plot vertices */ 1268 PetscCall(VecGetArray(coordinates, &coords)); 1269 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1270 for (v = vStart; v < vEnd; ++v) { 1271 PetscInt off, dof, d; 1272 PetscBool isLabeled = PETSC_FALSE; 1273 1274 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1275 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1276 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1277 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1278 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1279 for (d = 0; d < dof; ++d) { 1280 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1281 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1282 } 1283 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1284 if (dim == 3) { 1285 PetscReal tmp = tcoords[1]; 1286 tcoords[1] = tcoords[2]; 1287 tcoords[2] = -tmp; 1288 } 1289 for (d = 0; d < dof; ++d) { 1290 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1291 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1292 } 1293 if (drawHasse) color = colors[0 % numColors]; 1294 else color = colors[rank % numColors]; 1295 for (l = 0; l < numLabels; ++l) { 1296 PetscInt val; 1297 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1298 if (val >= 0) { 1299 color = lcolors[l % numLColors]; 1300 isLabeled = PETSC_TRUE; 1301 break; 1302 } 1303 } 1304 if (drawNumbers[0]) { 1305 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1306 } else if (drawColors[0]) { 1307 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1308 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1309 } 1310 PetscCall(VecRestoreArray(coordinates, &coords)); 1311 PetscCall(PetscViewerFlush(viewer)); 1312 /* Plot edges */ 1313 if (plotEdges) { 1314 PetscCall(VecGetArray(coordinates, &coords)); 1315 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1316 for (e = eStart; e < eEnd; ++e) { 1317 const PetscInt *cone; 1318 PetscInt coneSize, offA, offB, dof, d; 1319 1320 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1321 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1322 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1323 PetscCall(DMPlexGetCone(dm, e, &cone)); 1324 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1325 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1326 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1327 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1328 for (d = 0; d < dof; ++d) { 1329 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1330 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1331 } 1332 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1333 if (dim == 3) { 1334 PetscReal tmp = tcoords[1]; 1335 tcoords[1] = tcoords[2]; 1336 tcoords[2] = -tmp; 1337 } 1338 for (d = 0; d < dof; ++d) { 1339 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1340 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1341 } 1342 if (drawHasse) color = colors[1 % numColors]; 1343 else color = colors[rank % numColors]; 1344 for (l = 0; l < numLabels; ++l) { 1345 PetscInt val; 1346 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1347 if (val >= 0) { 1348 color = lcolors[l % numLColors]; 1349 break; 1350 } 1351 } 1352 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1353 } 1354 PetscCall(VecRestoreArray(coordinates, &coords)); 1355 PetscCall(PetscViewerFlush(viewer)); 1356 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1357 } 1358 /* Plot cells */ 1359 if (dim == 3 || !drawNumbers[1]) { 1360 for (e = eStart; e < eEnd; ++e) { 1361 const PetscInt *cone; 1362 1363 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1364 color = colors[rank % numColors]; 1365 for (l = 0; l < numLabels; ++l) { 1366 PetscInt val; 1367 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1368 if (val >= 0) { 1369 color = lcolors[l % numLColors]; 1370 break; 1371 } 1372 } 1373 PetscCall(DMPlexGetCone(dm, e, &cone)); 1374 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1375 } 1376 } else { 1377 DMPolytopeType ct; 1378 1379 /* Drawing a 2D polygon */ 1380 for (c = cStart; c < cEnd; ++c) { 1381 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1382 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1383 if (DMPolytopeTypeIsHybrid(ct)) { 1384 const PetscInt *cone; 1385 PetscInt coneSize, e; 1386 1387 PetscCall(DMPlexGetCone(dm, c, &cone)); 1388 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1389 for (e = 0; e < coneSize; ++e) { 1390 const PetscInt *econe; 1391 1392 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1393 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)); 1394 } 1395 } else { 1396 PetscInt *closure = NULL; 1397 PetscInt closureSize, Nv = 0, v; 1398 1399 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1400 for (p = 0; p < closureSize * 2; p += 2) { 1401 const PetscInt point = closure[p]; 1402 1403 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1404 } 1405 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1406 for (v = 0; v <= Nv; ++v) { 1407 const PetscInt vertex = closure[v % Nv]; 1408 1409 if (v > 0) { 1410 if (plotEdges) { 1411 const PetscInt *edge; 1412 PetscInt endpoints[2], ne; 1413 1414 endpoints[0] = closure[v - 1]; 1415 endpoints[1] = vertex; 1416 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1417 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1418 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1419 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1420 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1421 } 1422 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1423 } 1424 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1425 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1426 } 1427 } 1428 } 1429 for (c = cStart; c < cEnd; ++c) { 1430 double ccoords[3] = {0.0, 0.0, 0.0}; 1431 PetscBool isLabeled = PETSC_FALSE; 1432 PetscScalar *cellCoords = NULL; 1433 const PetscScalar *array; 1434 PetscInt numCoords, cdim, d; 1435 PetscBool isDG; 1436 1437 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1438 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1439 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1440 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1441 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1442 for (p = 0; p < numCoords / cdim; ++p) { 1443 for (d = 0; d < cdim; ++d) { 1444 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1445 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1446 } 1447 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1448 if (cdim == 3) { 1449 PetscReal tmp = tcoords[1]; 1450 tcoords[1] = tcoords[2]; 1451 tcoords[2] = -tmp; 1452 } 1453 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1454 } 1455 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1456 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1457 for (d = 0; d < cdim; ++d) { 1458 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1459 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1460 } 1461 if (drawHasse) color = colors[depth % numColors]; 1462 else color = colors[rank % numColors]; 1463 for (l = 0; l < numLabels; ++l) { 1464 PetscInt val; 1465 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1466 if (val >= 0) { 1467 color = lcolors[l % numLColors]; 1468 isLabeled = PETSC_TRUE; 1469 break; 1470 } 1471 } 1472 if (drawNumbers[dim]) { 1473 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1474 } else if (drawColors[dim]) { 1475 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1476 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1477 } 1478 if (drawHasse) { 1479 int height = 0; 1480 1481 color = colors[depth % numColors]; 1482 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1483 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1484 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1485 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1486 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1487 1488 if (depth > 2) { 1489 color = colors[1 % numColors]; 1490 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1491 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1492 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1493 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1494 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1495 } 1496 1497 color = colors[1 % numColors]; 1498 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1499 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1500 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1502 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1503 1504 color = colors[0 % numColors]; 1505 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1506 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1507 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1510 1511 for (p = pStart; p < pEnd; ++p) { 1512 const PetscInt *cone; 1513 PetscInt coneSize, cp; 1514 1515 PetscCall(DMPlexGetCone(dm, p, &cone)); 1516 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1517 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1518 } 1519 } 1520 PetscCall(PetscViewerFlush(viewer)); 1521 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1522 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1523 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1524 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1525 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1526 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1527 PetscCall(PetscFree3(names, colors, lcolors)); 1528 PetscCall(PetscBTDestroy(&wp)); 1529 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1530 Vec cown, acown; 1531 VecScatter sct; 1532 ISLocalToGlobalMapping g2l; 1533 IS gid, acis; 1534 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1535 MPI_Group ggroup, ngroup; 1536 PetscScalar *array, nid; 1537 const PetscInt *idxs; 1538 PetscInt *idxs2, *start, *adjacency, *work; 1539 PetscInt64 lm[3], gm[3]; 1540 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1541 PetscMPIInt d1, d2, rank; 1542 1543 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1544 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1545 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1546 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1547 #endif 1548 if (ncomm != MPI_COMM_NULL) { 1549 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1550 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1551 d1 = 0; 1552 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1553 nid = d2; 1554 PetscCallMPI(MPI_Group_free(&ggroup)); 1555 PetscCallMPI(MPI_Group_free(&ngroup)); 1556 PetscCallMPI(MPI_Comm_free(&ncomm)); 1557 } else nid = 0.0; 1558 1559 /* Get connectivity */ 1560 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1561 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1562 1563 /* filter overlapped local cells */ 1564 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1565 PetscCall(ISGetIndices(gid, &idxs)); 1566 PetscCall(ISGetLocalSize(gid, &cum)); 1567 PetscCall(PetscMalloc1(cum, &idxs2)); 1568 for (c = cStart, cum = 0; c < cEnd; c++) { 1569 if (idxs[c - cStart] < 0) continue; 1570 idxs2[cum++] = idxs[c - cStart]; 1571 } 1572 PetscCall(ISRestoreIndices(gid, &idxs)); 1573 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1574 PetscCall(ISDestroy(&gid)); 1575 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1576 1577 /* support for node-aware cell locality */ 1578 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1579 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1580 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1581 PetscCall(VecGetArray(cown, &array)); 1582 for (c = 0; c < numVertices; c++) array[c] = nid; 1583 PetscCall(VecRestoreArray(cown, &array)); 1584 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1585 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1586 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1587 PetscCall(ISDestroy(&acis)); 1588 PetscCall(VecScatterDestroy(&sct)); 1589 PetscCall(VecDestroy(&cown)); 1590 1591 /* compute edgeCut */ 1592 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1593 PetscCall(PetscMalloc1(cum, &work)); 1594 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1595 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1596 PetscCall(ISDestroy(&gid)); 1597 PetscCall(VecGetArray(acown, &array)); 1598 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1599 PetscInt totl; 1600 1601 totl = start[c + 1] - start[c]; 1602 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1603 for (i = 0; i < totl; i++) { 1604 if (work[i] < 0) { 1605 ect += 1; 1606 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1607 } 1608 } 1609 } 1610 PetscCall(PetscFree(work)); 1611 PetscCall(VecRestoreArray(acown, &array)); 1612 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1613 lm[1] = -numVertices; 1614 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1615 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1616 lm[0] = ect; /* edgeCut */ 1617 lm[1] = ectn; /* node-aware edgeCut */ 1618 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1619 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1620 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1621 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1622 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1623 #else 1624 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1625 #endif 1626 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1627 PetscCall(PetscFree(start)); 1628 PetscCall(PetscFree(adjacency)); 1629 PetscCall(VecDestroy(&acown)); 1630 } else { 1631 const char *name; 1632 PetscInt *sizes, *hybsizes, *ghostsizes; 1633 PetscInt locDepth, depth, cellHeight, dim, d; 1634 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1635 PetscInt numLabels, l, maxSize = 17; 1636 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1637 MPI_Comm comm; 1638 PetscMPIInt size, rank; 1639 1640 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1641 PetscCallMPI(MPI_Comm_size(comm, &size)); 1642 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1643 PetscCall(DMGetDimension(dm, &dim)); 1644 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1645 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1646 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1647 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1648 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1649 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1650 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1651 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1652 gcNum = gcEnd - gcStart; 1653 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1654 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1655 for (d = 0; d <= depth; d++) { 1656 PetscInt Nc[2] = {0, 0}, ict; 1657 1658 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1659 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1660 ict = ct0; 1661 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1662 ct0 = (DMPolytopeType)ict; 1663 for (p = pStart; p < pEnd; ++p) { 1664 DMPolytopeType ct; 1665 1666 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1667 if (ct == ct0) ++Nc[0]; 1668 else ++Nc[1]; 1669 } 1670 if (size < maxSize) { 1671 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1672 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1673 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1674 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1675 for (p = 0; p < size; ++p) { 1676 if (rank == 0) { 1677 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1678 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1679 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1680 } 1681 } 1682 } else { 1683 PetscInt locMinMax[2]; 1684 1685 locMinMax[0] = Nc[0] + Nc[1]; 1686 locMinMax[1] = Nc[0] + Nc[1]; 1687 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1688 locMinMax[0] = Nc[1]; 1689 locMinMax[1] = Nc[1]; 1690 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1691 if (d == depth) { 1692 locMinMax[0] = gcNum; 1693 locMinMax[1] = gcNum; 1694 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1695 } 1696 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1697 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1698 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1699 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1700 } 1701 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1702 } 1703 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1704 { 1705 const PetscReal *maxCell; 1706 const PetscReal *L; 1707 PetscBool localized; 1708 1709 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1710 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1711 if (L || localized) { 1712 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1713 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1714 if (L) { 1715 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1716 for (d = 0; d < dim; ++d) { 1717 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1718 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1719 } 1720 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1721 } 1722 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1723 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1724 } 1725 } 1726 PetscCall(DMGetNumLabels(dm, &numLabels)); 1727 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1728 for (l = 0; l < numLabels; ++l) { 1729 DMLabel label; 1730 const char *name; 1731 PetscInt *values; 1732 PetscInt numValues, v; 1733 1734 PetscCall(DMGetLabelName(dm, l, &name)); 1735 PetscCall(DMGetLabel(dm, name, &label)); 1736 PetscCall(DMLabelGetNumValues(label, &numValues)); 1737 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1738 1739 { // Extract array of DMLabel values so it can be sorted 1740 IS is_values; 1741 const PetscInt *is_values_local = NULL; 1742 1743 PetscCall(DMLabelGetValueIS(label, &is_values)); 1744 PetscCall(ISGetIndices(is_values, &is_values_local)); 1745 PetscCall(PetscMalloc1(numValues, &values)); 1746 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1747 PetscCall(PetscSortInt(numValues, values)); 1748 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1749 PetscCall(ISDestroy(&is_values)); 1750 } 1751 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1752 for (v = 0; v < numValues; ++v) { 1753 PetscInt size; 1754 1755 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1756 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1757 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1758 } 1759 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1760 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1761 PetscCall(PetscFree(values)); 1762 } 1763 { 1764 char **labelNames; 1765 PetscInt Nl = numLabels; 1766 PetscBool flg; 1767 1768 PetscCall(PetscMalloc1(Nl, &labelNames)); 1769 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1770 for (l = 0; l < Nl; ++l) { 1771 DMLabel label; 1772 1773 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1774 if (flg) { 1775 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1776 PetscCall(DMLabelView(label, viewer)); 1777 } 1778 PetscCall(PetscFree(labelNames[l])); 1779 } 1780 PetscCall(PetscFree(labelNames)); 1781 } 1782 /* If no fields are specified, people do not want to see adjacency */ 1783 if (dm->Nf) { 1784 PetscInt f; 1785 1786 for (f = 0; f < dm->Nf; ++f) { 1787 const char *name; 1788 1789 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1790 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1791 PetscCall(PetscViewerASCIIPushTab(viewer)); 1792 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1793 if (dm->fields[f].adjacency[0]) { 1794 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1795 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1796 } else { 1797 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1798 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1799 } 1800 PetscCall(PetscViewerASCIIPopTab(viewer)); 1801 } 1802 } 1803 DMPlexTransform tr; 1804 1805 PetscCall(DMPlexGetTransform(dm, &tr)); 1806 if (tr) { 1807 PetscCall(PetscViewerASCIIPushTab(viewer)); 1808 PetscCall(PetscViewerASCIIPrintf(viewer, "Created using transform:\n")); 1809 PetscCall(DMPlexTransformView(tr, viewer)); 1810 PetscCall(PetscViewerASCIIPopTab(viewer)); 1811 } 1812 PetscCall(DMGetCoarseDM(dm, &cdm)); 1813 if (cdm) { 1814 PetscCall(PetscViewerASCIIPushTab(viewer)); 1815 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1816 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1817 PetscCall(PetscViewerASCIIPopTab(viewer)); 1818 } 1819 } 1820 PetscFunctionReturn(PETSC_SUCCESS); 1821 } 1822 1823 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt lC, PetscInt cC, PetscInt cell, const PetscScalar coords[]) 1824 { 1825 DMPolytopeType ct; 1826 PetscMPIInt rank; 1827 PetscInt cdim; 1828 int lineColor, cellColor; 1829 1830 PetscFunctionBegin; 1831 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1832 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1833 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1834 lineColor = (int)(lC < 0 ? PETSC_DRAW_BLACK : lC); 1835 cellColor = (int)(cC < 0 ? PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2 : cC); 1836 switch (ct) { 1837 case DM_POLYTOPE_SEGMENT: 1838 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1839 switch (cdim) { 1840 case 1: { 1841 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1842 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1843 1844 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, lineColor)); 1845 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, lineColor)); 1846 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, lineColor)); 1847 } break; 1848 case 2: { 1849 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1850 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1851 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1852 1853 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1854 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, lineColor)); 1855 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, lineColor)); 1856 } break; 1857 default: 1858 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1859 } 1860 break; 1861 case DM_POLYTOPE_TRIANGLE: 1862 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1863 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1864 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1865 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1866 break; 1867 case DM_POLYTOPE_QUADRILATERAL: 1868 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1869 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), cellColor, cellColor, cellColor)); 1870 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1871 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1872 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor)); 1873 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1874 break; 1875 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1876 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1877 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1878 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1879 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor)); 1880 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1881 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1882 break; 1883 case DM_POLYTOPE_FV_GHOST: 1884 break; 1885 default: 1886 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1887 } 1888 PetscFunctionReturn(PETSC_SUCCESS); 1889 } 1890 1891 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1892 { 1893 PetscReal centroid[2] = {0., 0.}; 1894 PetscMPIInt rank; 1895 PetscMPIInt fillColor; 1896 1897 PetscFunctionBegin; 1898 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1899 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1900 for (PetscInt v = 0; v < Nv; ++v) { 1901 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1902 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1903 } 1904 for (PetscInt e = 0; e < Nv; ++e) { 1905 refCoords[0] = refVertices[e * 2 + 0]; 1906 refCoords[1] = refVertices[e * 2 + 1]; 1907 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1908 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1909 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1910 } 1911 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1912 for (PetscInt d = 0; d < edgeDiv; ++d) { 1913 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)); 1914 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1915 } 1916 } 1917 PetscFunctionReturn(PETSC_SUCCESS); 1918 } 1919 1920 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1921 { 1922 DMPolytopeType ct; 1923 1924 PetscFunctionBegin; 1925 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1926 switch (ct) { 1927 case DM_POLYTOPE_TRIANGLE: { 1928 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1929 1930 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1931 } break; 1932 case DM_POLYTOPE_QUADRILATERAL: { 1933 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1934 1935 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1936 } break; 1937 default: 1938 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1939 } 1940 PetscFunctionReturn(PETSC_SUCCESS); 1941 } 1942 1943 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1944 { 1945 PetscDraw draw; 1946 DM cdm; 1947 PetscSection coordSection; 1948 Vec coordinates; 1949 PetscReal xyl[3], xyr[3]; 1950 PetscReal *refCoords, *edgeCoords; 1951 PetscBool isnull, drawAffine; 1952 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv, lineColor = PETSC_DETERMINE, cellColor = PETSC_DETERMINE; 1953 1954 PetscFunctionBegin; 1955 PetscCall(DMGetCoordinateDim(dm, &dim)); 1956 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1957 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1958 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1959 edgeDiv = cDegree + 1; 1960 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_line_color", &lineColor, NULL)); 1961 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_cell_color", &cellColor, NULL)); 1962 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1963 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1964 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1965 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1966 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1967 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1968 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1969 1970 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1971 PetscCall(PetscDrawIsNull(draw, &isnull)); 1972 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1973 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1974 1975 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1976 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1977 PetscCall(PetscDrawClear(draw)); 1978 1979 for (c = cStart; c < cEnd; ++c) { 1980 PetscScalar *coords = NULL; 1981 const PetscScalar *coords_arr; 1982 PetscInt numCoords; 1983 PetscBool isDG; 1984 1985 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1986 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, lineColor, cellColor, c, coords)); 1987 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1988 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1989 } 1990 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1991 PetscCall(PetscDrawFlush(draw)); 1992 PetscCall(PetscDrawPause(draw)); 1993 PetscCall(PetscDrawSave(draw)); 1994 PetscFunctionReturn(PETSC_SUCCESS); 1995 } 1996 1997 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1998 { 1999 DM odm = dm, rdm = dm, cdm; 2000 PetscFE fe; 2001 PetscSpace sp; 2002 PetscClassId id; 2003 PetscInt degree; 2004 PetscBool hoView = PETSC_TRUE; 2005 2006 PetscFunctionBegin; 2007 PetscObjectOptionsBegin((PetscObject)dm); 2008 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 2009 PetscOptionsEnd(); 2010 PetscCall(PetscObjectReference((PetscObject)dm)); 2011 *hdm = dm; 2012 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 2013 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2014 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 2015 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 2016 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 2017 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 2018 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 2019 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 2020 DM cdm, rcdm; 2021 Mat In; 2022 Vec cl, rcl; 2023 2024 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 2025 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, PETSC_FALSE)); 2026 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 2027 PetscCall(DMGetCoordinateDM(odm, &cdm)); 2028 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 2029 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 2030 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 2031 PetscCall(DMSetCoarseDM(rcdm, cdm)); 2032 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 2033 PetscCall(MatMult(In, cl, rcl)); 2034 PetscCall(MatDestroy(&In)); 2035 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 2036 PetscCall(DMDestroy(&odm)); 2037 odm = rdm; 2038 } 2039 *hdm = rdm; 2040 PetscFunctionReturn(PETSC_SUCCESS); 2041 } 2042 2043 #if defined(PETSC_HAVE_EXODUSII) 2044 #include <exodusII.h> 2045 #include <petscviewerexodusii.h> 2046 #endif 2047 2048 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 2049 { 2050 PetscBool isascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 2051 char name[PETSC_MAX_PATH_LEN]; 2052 2053 PetscFunctionBegin; 2054 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2055 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2056 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 2057 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2058 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2059 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2060 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 2061 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 2062 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 2063 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2064 if (isascii) { 2065 PetscViewerFormat format; 2066 PetscCall(PetscViewerGetFormat(viewer, &format)); 2067 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 2068 else PetscCall(DMPlexView_Ascii(dm, viewer)); 2069 } else if (ishdf5) { 2070 #if defined(PETSC_HAVE_HDF5) 2071 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 2072 #else 2073 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2074 #endif 2075 } else if (isvtk) { 2076 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2077 } else if (isdraw) { 2078 DM hdm; 2079 2080 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2081 PetscCall(DMPlexView_Draw(hdm, viewer)); 2082 PetscCall(DMDestroy(&hdm)); 2083 } else if (isglvis) { 2084 PetscCall(DMPlexView_GLVis(dm, viewer)); 2085 #if defined(PETSC_HAVE_EXODUSII) 2086 } else if (isexodus) { 2087 /* 2088 ExodusII requires that all sets be part of exactly one cell set. 2089 If the dm does not have a "Cell Sets" label defined, we create one 2090 with ID 1, containing all cells. 2091 Note that if the Cell Sets label is defined but does not cover all cells, 2092 we may still have a problem. This should probably be checked here or in the viewer; 2093 */ 2094 PetscInt numCS; 2095 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2096 if (!numCS) { 2097 PetscInt cStart, cEnd, c; 2098 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2099 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2100 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2101 } 2102 PetscCall(DMView_PlexExodusII(dm, viewer)); 2103 #endif 2104 #if defined(PETSC_HAVE_CGNS) 2105 } else if (iscgns) { 2106 PetscCall(DMView_PlexCGNS(dm, viewer)); 2107 #endif 2108 } else if (ispython) { 2109 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2110 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2111 /* Optionally view the partition */ 2112 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2113 if (flg) { 2114 Vec ranks; 2115 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2116 PetscCall(VecView(ranks, viewer)); 2117 PetscCall(VecDestroy(&ranks)); 2118 } 2119 /* Optionally view a label */ 2120 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2121 if (flg) { 2122 DMLabel label; 2123 Vec val; 2124 2125 PetscCall(DMGetLabel(dm, name, &label)); 2126 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2127 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2128 PetscCall(VecView(val, viewer)); 2129 PetscCall(VecDestroy(&val)); 2130 } 2131 PetscFunctionReturn(PETSC_SUCCESS); 2132 } 2133 2134 /*@ 2135 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2136 2137 Collective 2138 2139 Input Parameters: 2140 + dm - The `DM` whose topology is to be saved 2141 - viewer - The `PetscViewer` to save it in 2142 2143 Level: advanced 2144 2145 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2146 @*/ 2147 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2148 { 2149 PetscBool ishdf5; 2150 2151 PetscFunctionBegin; 2152 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2153 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2154 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2155 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2156 if (ishdf5) { 2157 #if defined(PETSC_HAVE_HDF5) 2158 IS globalPointNumbering; 2159 PetscViewerFormat format; 2160 2161 PetscCall(PetscViewerGetFormat(viewer, &format)); 2162 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2163 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2164 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2165 PetscCall(ISDestroy(&globalPointNumbering)); 2166 #else 2167 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2168 #endif 2169 } 2170 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2171 PetscFunctionReturn(PETSC_SUCCESS); 2172 } 2173 2174 /*@ 2175 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2176 2177 Collective 2178 2179 Input Parameters: 2180 + dm - The `DM` whose coordinates are to be saved 2181 - viewer - The `PetscViewer` for saving 2182 2183 Level: advanced 2184 2185 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2186 @*/ 2187 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2188 { 2189 PetscBool ishdf5; 2190 2191 PetscFunctionBegin; 2192 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2193 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2194 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2195 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2196 if (ishdf5) { 2197 #if defined(PETSC_HAVE_HDF5) 2198 PetscViewerFormat format; 2199 2200 PetscCall(PetscViewerGetFormat(viewer, &format)); 2201 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2202 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2203 #else 2204 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2205 #endif 2206 } 2207 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2208 PetscFunctionReturn(PETSC_SUCCESS); 2209 } 2210 2211 /*@ 2212 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2213 2214 Collective 2215 2216 Input Parameters: 2217 + dm - The `DM` whose labels are to be saved 2218 - viewer - The `PetscViewer` for saving 2219 2220 Level: advanced 2221 2222 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2223 @*/ 2224 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2225 { 2226 PetscBool ishdf5; 2227 2228 PetscFunctionBegin; 2229 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2230 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2231 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2232 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2233 if (ishdf5) { 2234 #if defined(PETSC_HAVE_HDF5) 2235 IS globalPointNumbering; 2236 PetscViewerFormat format; 2237 2238 PetscCall(PetscViewerGetFormat(viewer, &format)); 2239 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2240 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2241 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2242 PetscCall(ISDestroy(&globalPointNumbering)); 2243 #else 2244 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2245 #endif 2246 } 2247 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2248 PetscFunctionReturn(PETSC_SUCCESS); 2249 } 2250 2251 /*@ 2252 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2253 2254 Collective 2255 2256 Input Parameters: 2257 + dm - The `DM` that contains the topology on which the section to be saved is defined 2258 . viewer - The `PetscViewer` for saving 2259 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2260 2261 Level: advanced 2262 2263 Notes: 2264 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. 2265 2266 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. 2267 2268 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2269 @*/ 2270 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2271 { 2272 PetscBool ishdf5; 2273 2274 PetscFunctionBegin; 2275 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2276 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2277 if (!sectiondm) sectiondm = dm; 2278 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2279 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2280 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2281 if (ishdf5) { 2282 #if defined(PETSC_HAVE_HDF5) 2283 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2284 #else 2285 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2286 #endif 2287 } 2288 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2289 PetscFunctionReturn(PETSC_SUCCESS); 2290 } 2291 2292 /*@ 2293 DMPlexGlobalVectorView - Saves a global vector 2294 2295 Collective 2296 2297 Input Parameters: 2298 + dm - The `DM` that represents the topology 2299 . viewer - The `PetscViewer` to save data with 2300 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2301 - vec - The global vector to be saved 2302 2303 Level: advanced 2304 2305 Notes: 2306 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. 2307 2308 Calling sequence: 2309 .vb 2310 DMCreate(PETSC_COMM_WORLD, &dm); 2311 DMSetType(dm, DMPLEX); 2312 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2313 DMClone(dm, §iondm); 2314 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2315 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2316 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2317 PetscSectionSetChart(section, pStart, pEnd); 2318 PetscSectionSetUp(section); 2319 DMSetLocalSection(sectiondm, section); 2320 PetscSectionDestroy(§ion); 2321 DMGetGlobalVector(sectiondm, &vec); 2322 PetscObjectSetName((PetscObject)vec, "vec_name"); 2323 DMPlexTopologyView(dm, viewer); 2324 DMPlexSectionView(dm, viewer, sectiondm); 2325 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2326 DMRestoreGlobalVector(sectiondm, &vec); 2327 DMDestroy(§iondm); 2328 DMDestroy(&dm); 2329 .ve 2330 2331 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2332 @*/ 2333 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2334 { 2335 PetscBool ishdf5; 2336 2337 PetscFunctionBegin; 2338 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2339 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2340 if (!sectiondm) sectiondm = dm; 2341 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2342 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2343 /* Check consistency */ 2344 { 2345 PetscSection section; 2346 PetscBool includesConstraints; 2347 PetscInt m, m1; 2348 2349 PetscCall(VecGetLocalSize(vec, &m1)); 2350 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2351 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2352 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2353 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2354 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2355 } 2356 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2357 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2358 if (ishdf5) { 2359 #if defined(PETSC_HAVE_HDF5) 2360 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2361 #else 2362 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2363 #endif 2364 } 2365 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2366 PetscFunctionReturn(PETSC_SUCCESS); 2367 } 2368 2369 /*@ 2370 DMPlexLocalVectorView - Saves a local vector 2371 2372 Collective 2373 2374 Input Parameters: 2375 + dm - The `DM` that represents the topology 2376 . viewer - The `PetscViewer` to save data with 2377 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2378 - vec - The local vector to be saved 2379 2380 Level: advanced 2381 2382 Note: 2383 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. 2384 2385 Calling sequence: 2386 .vb 2387 DMCreate(PETSC_COMM_WORLD, &dm); 2388 DMSetType(dm, DMPLEX); 2389 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2390 DMClone(dm, §iondm); 2391 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2392 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2393 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2394 PetscSectionSetChart(section, pStart, pEnd); 2395 PetscSectionSetUp(section); 2396 DMSetLocalSection(sectiondm, section); 2397 DMGetLocalVector(sectiondm, &vec); 2398 PetscObjectSetName((PetscObject)vec, "vec_name"); 2399 DMPlexTopologyView(dm, viewer); 2400 DMPlexSectionView(dm, viewer, sectiondm); 2401 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2402 DMRestoreLocalVector(sectiondm, &vec); 2403 DMDestroy(§iondm); 2404 DMDestroy(&dm); 2405 .ve 2406 2407 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2408 @*/ 2409 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2410 { 2411 PetscBool ishdf5; 2412 2413 PetscFunctionBegin; 2414 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2415 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2416 if (!sectiondm) sectiondm = dm; 2417 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2418 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2419 /* Check consistency */ 2420 { 2421 PetscSection section; 2422 PetscBool includesConstraints; 2423 PetscInt m, m1; 2424 2425 PetscCall(VecGetLocalSize(vec, &m1)); 2426 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2427 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2428 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2429 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2430 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2431 } 2432 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2433 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2434 if (ishdf5) { 2435 #if defined(PETSC_HAVE_HDF5) 2436 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2437 #else 2438 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2439 #endif 2440 } 2441 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2442 PetscFunctionReturn(PETSC_SUCCESS); 2443 } 2444 2445 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2446 { 2447 PetscBool ishdf5; 2448 2449 PetscFunctionBegin; 2450 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2451 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2452 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2453 if (ishdf5) { 2454 #if defined(PETSC_HAVE_HDF5) 2455 PetscViewerFormat format; 2456 PetscCall(PetscViewerGetFormat(viewer, &format)); 2457 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2458 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2459 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2460 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2461 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2462 PetscFunctionReturn(PETSC_SUCCESS); 2463 #else 2464 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2465 #endif 2466 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2467 } 2468 2469 /*@ 2470 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2471 2472 Collective 2473 2474 Input Parameters: 2475 + dm - The `DM` into which the topology is loaded 2476 - viewer - The `PetscViewer` for the saved topology 2477 2478 Output Parameter: 2479 . 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; 2480 `NULL` if unneeded 2481 2482 Level: advanced 2483 2484 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2485 `PetscViewer`, `PetscSF` 2486 @*/ 2487 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2488 { 2489 PetscBool ishdf5; 2490 2491 PetscFunctionBegin; 2492 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2493 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2494 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2495 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2496 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2497 if (ishdf5) { 2498 #if defined(PETSC_HAVE_HDF5) 2499 PetscViewerFormat format; 2500 2501 PetscCall(PetscViewerGetFormat(viewer, &format)); 2502 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2503 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2504 #else 2505 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2506 #endif 2507 } 2508 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2509 PetscFunctionReturn(PETSC_SUCCESS); 2510 } 2511 2512 /*@ 2513 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2514 2515 Collective 2516 2517 Input Parameters: 2518 + dm - The `DM` into which the coordinates are loaded 2519 . viewer - The `PetscViewer` for the saved coordinates 2520 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2521 2522 Level: advanced 2523 2524 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2525 `PetscSF`, `PetscViewer` 2526 @*/ 2527 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2528 { 2529 PetscBool ishdf5; 2530 2531 PetscFunctionBegin; 2532 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2533 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2534 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2535 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2536 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2537 if (ishdf5) { 2538 #if defined(PETSC_HAVE_HDF5) 2539 PetscViewerFormat format; 2540 2541 PetscCall(PetscViewerGetFormat(viewer, &format)); 2542 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2543 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2544 #else 2545 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2546 #endif 2547 } 2548 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2549 PetscFunctionReturn(PETSC_SUCCESS); 2550 } 2551 2552 /*@ 2553 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2554 2555 Collective 2556 2557 Input Parameters: 2558 + dm - The `DM` into which the labels are loaded 2559 . viewer - The `PetscViewer` for the saved labels 2560 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2561 2562 Level: advanced 2563 2564 Note: 2565 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2566 2567 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2568 `PetscSF`, `PetscViewer` 2569 @*/ 2570 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2571 { 2572 PetscBool ishdf5; 2573 2574 PetscFunctionBegin; 2575 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2576 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2577 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2578 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2579 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2580 if (ishdf5) { 2581 #if defined(PETSC_HAVE_HDF5) 2582 PetscViewerFormat format; 2583 2584 PetscCall(PetscViewerGetFormat(viewer, &format)); 2585 PetscCheck(format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2586 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2587 #else 2588 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2589 #endif 2590 } 2591 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2592 PetscFunctionReturn(PETSC_SUCCESS); 2593 } 2594 2595 /*@ 2596 DMPlexSectionLoad - Loads section into a `DMPLEX` 2597 2598 Collective 2599 2600 Input Parameters: 2601 + dm - The `DM` that represents the topology 2602 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2603 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2604 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2605 2606 Output Parameters: 2607 + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed) 2608 - localDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed) 2609 2610 Level: advanced 2611 2612 Notes: 2613 This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2614 2615 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2616 2617 The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2618 2619 Example using 2 processes: 2620 .vb 2621 NX (number of points on dm): 4 2622 sectionA : the on-disk section 2623 vecA : a vector associated with sectionA 2624 sectionB : sectiondm's local section constructed in this function 2625 vecB (local) : a vector associated with sectiondm's local section 2626 vecB (global) : a vector associated with sectiondm's global section 2627 2628 rank 0 rank 1 2629 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2630 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2631 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2632 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2633 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2634 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2635 sectionB->atlasDof : 1 0 1 | 1 3 2636 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2637 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2638 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2639 .ve 2640 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2641 2642 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2643 @*/ 2644 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, PeOp DM sectiondm, PetscSF globalToLocalPointSF, PeOp PetscSF *globalDofSF, PeOp PetscSF *localDofSF) 2645 { 2646 PetscBool ishdf5; 2647 2648 PetscFunctionBegin; 2649 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2650 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2651 if (!sectiondm) sectiondm = dm; 2652 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2653 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2654 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2655 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2656 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2657 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2658 if (ishdf5) { 2659 #if defined(PETSC_HAVE_HDF5) 2660 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2661 #else 2662 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2663 #endif 2664 } 2665 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2666 PetscFunctionReturn(PETSC_SUCCESS); 2667 } 2668 2669 /*@ 2670 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2671 2672 Collective 2673 2674 Input Parameters: 2675 + dm - The `DM` that represents the topology 2676 . viewer - The `PetscViewer` that represents the on-disk vector data 2677 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2678 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2679 - vec - The global vector to set values of 2680 2681 Level: advanced 2682 2683 Notes: 2684 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2685 2686 Calling sequence: 2687 .vb 2688 DMCreate(PETSC_COMM_WORLD, &dm); 2689 DMSetType(dm, DMPLEX); 2690 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2691 DMPlexTopologyLoad(dm, viewer, &sfX); 2692 DMClone(dm, §iondm); 2693 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2694 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2695 DMGetGlobalVector(sectiondm, &vec); 2696 PetscObjectSetName((PetscObject)vec, "vec_name"); 2697 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2698 DMRestoreGlobalVector(sectiondm, &vec); 2699 PetscSFDestroy(&gsf); 2700 PetscSFDestroy(&sfX); 2701 DMDestroy(§iondm); 2702 DMDestroy(&dm); 2703 .ve 2704 2705 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2706 `PetscSF`, `PetscViewer` 2707 @*/ 2708 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2709 { 2710 PetscBool ishdf5; 2711 2712 PetscFunctionBegin; 2713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2714 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2715 if (!sectiondm) sectiondm = dm; 2716 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2717 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2718 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2719 /* Check consistency */ 2720 { 2721 PetscSection section; 2722 PetscBool includesConstraints; 2723 PetscInt m, m1; 2724 2725 PetscCall(VecGetLocalSize(vec, &m1)); 2726 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2727 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2728 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2729 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2730 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2731 } 2732 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2733 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2734 if (ishdf5) { 2735 #if defined(PETSC_HAVE_HDF5) 2736 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2737 #else 2738 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2739 #endif 2740 } 2741 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2742 PetscFunctionReturn(PETSC_SUCCESS); 2743 } 2744 2745 /*@ 2746 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2747 2748 Collective 2749 2750 Input Parameters: 2751 + dm - The `DM` that represents the topology 2752 . viewer - The `PetscViewer` that represents the on-disk vector data 2753 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2754 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2755 - vec - The local vector to set values of 2756 2757 Level: advanced 2758 2759 Notes: 2760 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2761 2762 Calling sequence: 2763 .vb 2764 DMCreate(PETSC_COMM_WORLD, &dm); 2765 DMSetType(dm, DMPLEX); 2766 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2767 DMPlexTopologyLoad(dm, viewer, &sfX); 2768 DMClone(dm, §iondm); 2769 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2770 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2771 DMGetLocalVector(sectiondm, &vec); 2772 PetscObjectSetName((PetscObject)vec, "vec_name"); 2773 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2774 DMRestoreLocalVector(sectiondm, &vec); 2775 PetscSFDestroy(&lsf); 2776 PetscSFDestroy(&sfX); 2777 DMDestroy(§iondm); 2778 DMDestroy(&dm); 2779 .ve 2780 2781 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2782 `PetscSF`, `PetscViewer` 2783 @*/ 2784 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2785 { 2786 PetscBool ishdf5; 2787 2788 PetscFunctionBegin; 2789 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2790 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2791 if (!sectiondm) sectiondm = dm; 2792 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2793 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2794 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2795 /* Check consistency */ 2796 { 2797 PetscSection section; 2798 PetscBool includesConstraints; 2799 PetscInt m, m1; 2800 2801 PetscCall(VecGetLocalSize(vec, &m1)); 2802 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2803 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2804 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2805 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2806 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2807 } 2808 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2809 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2810 if (ishdf5) { 2811 #if defined(PETSC_HAVE_HDF5) 2812 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2813 #else 2814 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2815 #endif 2816 } 2817 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2818 PetscFunctionReturn(PETSC_SUCCESS); 2819 } 2820 2821 PetscErrorCode DMDestroy_Plex(DM dm) 2822 { 2823 DM_Plex *mesh = (DM_Plex *)dm->data; 2824 2825 PetscFunctionBegin; 2826 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2827 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2828 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2829 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBounds_C", NULL)); 2830 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2831 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2832 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2833 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2834 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2835 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2836 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2837 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2838 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2839 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2840 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2841 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2842 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2843 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2844 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2845 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2846 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2847 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2848 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2849 PetscCall(PetscFree(mesh->cones)); 2850 PetscCall(PetscFree(mesh->coneOrientations)); 2851 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2852 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2853 PetscCall(PetscFree(mesh->supports)); 2854 PetscCall(PetscFree(mesh->cellTypes)); 2855 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2856 PetscCall(PetscFree(mesh->tetgenOpts)); 2857 PetscCall(PetscFree(mesh->triangleOpts)); 2858 PetscCall(PetscFree(mesh->transformType)); 2859 PetscCall(PetscFree(mesh->distributionName)); 2860 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2861 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2862 PetscCall(ISDestroy(&mesh->subpointIS)); 2863 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2864 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2865 if (mesh->periodic.face_sfs) { 2866 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2867 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2868 } 2869 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2870 if (mesh->periodic.periodic_points) { 2871 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2872 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2873 } 2874 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2875 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2876 PetscCall(ISDestroy(&mesh->anchorIS)); 2877 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2878 PetscCall(PetscFree(mesh->parents)); 2879 PetscCall(PetscFree(mesh->childIDs)); 2880 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2881 PetscCall(PetscFree(mesh->children)); 2882 PetscCall(DMDestroy(&mesh->referenceTree)); 2883 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2884 PetscCall(PetscFree(mesh->neighbors)); 2885 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2886 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2887 PetscCall(DMPlexTransformDestroy(&mesh->transform)); 2888 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2889 PetscCall(PetscFree(mesh)); 2890 PetscFunctionReturn(PETSC_SUCCESS); 2891 } 2892 2893 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2894 { 2895 PetscSection sectionGlobal, sectionLocal; 2896 PetscInt bs = -1, mbs; 2897 PetscInt localSize, localStart = 0; 2898 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2899 MatType mtype; 2900 ISLocalToGlobalMapping ltog; 2901 2902 PetscFunctionBegin; 2903 PetscCall(MatInitializePackage()); 2904 mtype = dm->mattype; 2905 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2906 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2907 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2908 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2909 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2910 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2911 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2912 PetscCall(MatSetType(*J, mtype)); 2913 PetscCall(MatSetFromOptions(*J)); 2914 PetscCall(MatGetBlockSize(*J, &mbs)); 2915 if (mbs > 1) bs = mbs; 2916 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2917 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2918 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2919 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2920 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2921 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2922 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2923 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2924 if (!isShell) { 2925 // There are three states with pblocks, since block starts can have no dofs: 2926 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2927 // TRUE) Block Start: The first entry in a block has been added 2928 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2929 PetscBT blst; 2930 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2931 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2932 const PetscInt *perm = NULL; 2933 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2934 PetscInt pStart, pEnd, dof, cdof, num_fields; 2935 2936 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2937 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2938 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2939 2940 PetscCall(PetscCalloc1(localSize, &pblocks)); 2941 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2942 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2943 // We need to process in the permuted order to get block sizes right 2944 for (PetscInt point = pStart; point < pEnd; ++point) { 2945 const PetscInt p = perm ? perm[point] : point; 2946 2947 switch (dm->blocking_type) { 2948 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2949 PetscInt bdof, offset; 2950 2951 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2952 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2953 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2954 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2955 if (dof > 0) { 2956 // State change 2957 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2958 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2959 2960 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2961 // Signal block concatenation 2962 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2963 } 2964 dof = dof < 0 ? -(dof + 1) : dof; 2965 bdof = cdof && (dof - cdof) ? 1 : dof; 2966 if (dof) { 2967 if (bs < 0) { 2968 bs = bdof; 2969 } else if (bs != bdof) { 2970 bs = 1; 2971 } 2972 } 2973 } break; 2974 case DM_BLOCKING_FIELD_NODE: { 2975 for (PetscInt field = 0; field < num_fields; field++) { 2976 PetscInt num_comp, bdof, offset; 2977 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2978 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2979 if (dof < 0) continue; 2980 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2981 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2982 PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp); 2983 PetscInt num_nodes = dof / num_comp; 2984 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2985 // Handle possibly constant block size (unlikely) 2986 bdof = cdof && (dof - cdof) ? 1 : dof; 2987 if (dof) { 2988 if (bs < 0) { 2989 bs = bdof; 2990 } else if (bs != bdof) { 2991 bs = 1; 2992 } 2993 } 2994 } 2995 } break; 2996 } 2997 } 2998 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2999 /* Must have same blocksize on all procs (some might have no points) */ 3000 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 3001 bsLocal[1] = bs; 3002 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 3003 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 3004 else bs = bsMinMax[0]; 3005 bs = PetscMax(1, bs); 3006 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 3007 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 3008 PetscCall(MatSetBlockSize(*J, bs)); 3009 PetscCall(MatSetUp(*J)); 3010 } else { 3011 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 3012 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 3013 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 3014 } 3015 if (pblocks) { // Consolidate blocks 3016 PetscInt nblocks = 0; 3017 pblocks[0] = PetscAbs(pblocks[0]); 3018 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 3019 if (pblocks[i] == 0) continue; 3020 // Negative block size indicates the blocks should be concatenated 3021 if (pblocks[i] < 0) { 3022 pblocks[i] = -pblocks[i]; 3023 pblocks[nblocks - 1] += pblocks[i]; 3024 } else { 3025 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 3026 } 3027 for (PetscInt j = 1; j < pblocks[i]; j++) 3028 PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j); 3029 } 3030 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 3031 } 3032 PetscCall(PetscFree(pblocks)); 3033 } 3034 PetscCall(MatSetDM(*J, dm)); 3035 PetscFunctionReturn(PETSC_SUCCESS); 3036 } 3037 3038 /*@ 3039 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 3040 3041 Not Collective 3042 3043 Input Parameter: 3044 . dm - The `DMPLEX` 3045 3046 Output Parameter: 3047 . subsection - The subdomain section 3048 3049 Level: developer 3050 3051 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 3052 @*/ 3053 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 3054 { 3055 DM_Plex *mesh = (DM_Plex *)dm->data; 3056 3057 PetscFunctionBegin; 3058 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3059 if (!mesh->subdomainSection) { 3060 PetscSection section; 3061 PetscSF sf; 3062 3063 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 3064 PetscCall(DMGetLocalSection(dm, §ion)); 3065 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 3066 PetscCall(PetscSFDestroy(&sf)); 3067 } 3068 *subsection = mesh->subdomainSection; 3069 PetscFunctionReturn(PETSC_SUCCESS); 3070 } 3071 3072 /*@ 3073 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 3074 3075 Not Collective 3076 3077 Input Parameter: 3078 . dm - The `DMPLEX` 3079 3080 Output Parameters: 3081 + pStart - The first mesh point 3082 - pEnd - The upper bound for mesh points 3083 3084 Level: beginner 3085 3086 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3087 @*/ 3088 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3089 { 3090 DM_Plex *mesh = (DM_Plex *)dm->data; 3091 3092 PetscFunctionBegin; 3093 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3094 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3095 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3096 PetscFunctionReturn(PETSC_SUCCESS); 3097 } 3098 3099 /*@ 3100 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3101 3102 Not Collective 3103 3104 Input Parameters: 3105 + dm - The `DMPLEX` 3106 . pStart - The first mesh point 3107 - pEnd - The upper bound for mesh points 3108 3109 Level: beginner 3110 3111 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3112 @*/ 3113 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3114 { 3115 DM_Plex *mesh = (DM_Plex *)dm->data; 3116 3117 PetscFunctionBegin; 3118 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3119 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3120 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3121 PetscCall(PetscFree(mesh->cellTypes)); 3122 PetscFunctionReturn(PETSC_SUCCESS); 3123 } 3124 3125 /*@ 3126 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3127 3128 Not Collective 3129 3130 Input Parameters: 3131 + dm - The `DMPLEX` 3132 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3133 3134 Output Parameter: 3135 . size - The cone size for point `p` 3136 3137 Level: beginner 3138 3139 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3140 @*/ 3141 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3142 { 3143 DM_Plex *mesh = (DM_Plex *)dm->data; 3144 3145 PetscFunctionBegin; 3146 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3147 PetscAssertPointer(size, 3); 3148 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3149 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3150 PetscFunctionReturn(PETSC_SUCCESS); 3151 } 3152 3153 /*@ 3154 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3155 3156 Not Collective 3157 3158 Input Parameters: 3159 + dm - The `DMPLEX` 3160 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3161 - size - The cone size for point `p` 3162 3163 Level: beginner 3164 3165 Note: 3166 This should be called after `DMPlexSetChart()`. 3167 3168 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3169 @*/ 3170 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3171 { 3172 DM_Plex *mesh = (DM_Plex *)dm->data; 3173 3174 PetscFunctionBegin; 3175 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3176 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3177 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3178 PetscFunctionReturn(PETSC_SUCCESS); 3179 } 3180 3181 /*@C 3182 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3183 3184 Not Collective 3185 3186 Input Parameters: 3187 + dm - The `DMPLEX` 3188 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3189 3190 Output Parameter: 3191 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3192 3193 Level: beginner 3194 3195 Fortran Notes: 3196 `cone` must be declared with 3197 .vb 3198 PetscInt, pointer :: cone(:) 3199 .ve 3200 3201 You must call `DMPlexRestoreCone()` after you finish using the array. 3202 `DMPlexRestoreCone()` is not needed/available in C. 3203 3204 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3205 @*/ 3206 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3207 { 3208 DM_Plex *mesh = (DM_Plex *)dm->data; 3209 PetscInt off; 3210 3211 PetscFunctionBegin; 3212 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3213 PetscAssertPointer(cone, 3); 3214 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3215 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3216 PetscFunctionReturn(PETSC_SUCCESS); 3217 } 3218 3219 /*@ 3220 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3221 3222 Not Collective 3223 3224 Input Parameters: 3225 + dm - The `DMPLEX` 3226 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3227 3228 Output Parameters: 3229 + pConesSection - `PetscSection` describing the layout of `pCones` 3230 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3231 3232 Level: intermediate 3233 3234 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3235 @*/ 3236 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PeOp PetscSection *pConesSection, PeOp IS *pCones) 3237 { 3238 PetscSection cs, newcs; 3239 PetscInt *cones; 3240 PetscInt *newarr = NULL; 3241 PetscInt n; 3242 3243 PetscFunctionBegin; 3244 PetscCall(DMPlexGetCones(dm, &cones)); 3245 PetscCall(DMPlexGetConeSection(dm, &cs)); 3246 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3247 if (pConesSection) *pConesSection = newcs; 3248 if (pCones) { 3249 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3250 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3251 } 3252 PetscFunctionReturn(PETSC_SUCCESS); 3253 } 3254 3255 /*@ 3256 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3257 3258 Not Collective 3259 3260 Input Parameters: 3261 + dm - The `DMPLEX` 3262 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3263 3264 Output Parameter: 3265 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3266 3267 Level: advanced 3268 3269 Notes: 3270 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3271 3272 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3273 3274 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3275 `DMPlexGetDepth()`, `IS` 3276 @*/ 3277 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3278 { 3279 IS *expandedPointsAll; 3280 PetscInt depth; 3281 3282 PetscFunctionBegin; 3283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3284 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3285 PetscAssertPointer(expandedPoints, 3); 3286 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3287 *expandedPoints = expandedPointsAll[0]; 3288 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3289 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3290 PetscFunctionReturn(PETSC_SUCCESS); 3291 } 3292 3293 /*@ 3294 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3295 (DAG points of depth 0, i.e., without cones). 3296 3297 Not Collective 3298 3299 Input Parameters: 3300 + dm - The `DMPLEX` 3301 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3302 3303 Output Parameters: 3304 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3305 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3306 - sections - (optional) An array of sections which describe mappings from points to their cone points 3307 3308 Level: advanced 3309 3310 Notes: 3311 Like `DMPlexGetConeTuple()` but recursive. 3312 3313 Array `expandedPoints` has size equal to `depth`. Each `expandedPoints`[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 3314 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3315 3316 Array section has size equal to `depth`. Each `PetscSection` `sections`[d] realizes mapping from `expandedPoints`[d+1] (section points) to `expandedPoints`[d] (section dofs) as follows\: 3317 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3318 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3319 3320 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3321 `DMPlexGetDepth()`, `PetscSection`, `IS` 3322 @*/ 3323 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3324 { 3325 const PetscInt *arr0 = NULL, *cone = NULL; 3326 PetscInt *arr = NULL, *newarr = NULL; 3327 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3328 IS *expandedPoints_; 3329 PetscSection *sections_; 3330 3331 PetscFunctionBegin; 3332 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3333 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3334 if (depth) PetscAssertPointer(depth, 3); 3335 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3336 if (sections) PetscAssertPointer(sections, 5); 3337 PetscCall(ISGetLocalSize(points, &n)); 3338 PetscCall(ISGetIndices(points, &arr0)); 3339 PetscCall(DMPlexGetDepth(dm, &depth_)); 3340 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3341 PetscCall(PetscCalloc1(depth_, §ions_)); 3342 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3343 for (d = depth_ - 1; d >= 0; d--) { 3344 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3345 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3346 for (i = 0; i < n; i++) { 3347 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3348 if (arr[i] >= start && arr[i] < end) { 3349 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3350 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3351 } else { 3352 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3353 } 3354 } 3355 PetscCall(PetscSectionSetUp(sections_[d])); 3356 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3357 PetscCall(PetscMalloc1(newn, &newarr)); 3358 for (i = 0; i < n; i++) { 3359 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3360 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3361 if (cn > 1) { 3362 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3363 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3364 } else { 3365 newarr[co] = arr[i]; 3366 } 3367 } 3368 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3369 arr = newarr; 3370 n = newn; 3371 } 3372 PetscCall(ISRestoreIndices(points, &arr0)); 3373 *depth = depth_; 3374 if (expandedPoints) *expandedPoints = expandedPoints_; 3375 else { 3376 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3377 PetscCall(PetscFree(expandedPoints_)); 3378 } 3379 if (sections) *sections = sections_; 3380 else { 3381 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3382 PetscCall(PetscFree(sections_)); 3383 } 3384 PetscFunctionReturn(PETSC_SUCCESS); 3385 } 3386 3387 /*@ 3388 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3389 3390 Not Collective 3391 3392 Input Parameters: 3393 + dm - The `DMPLEX` 3394 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3395 3396 Output Parameters: 3397 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3398 . expandedPoints - (optional) An array of recursively expanded cones 3399 - sections - (optional) An array of sections which describe mappings from points to their cone points 3400 3401 Level: advanced 3402 3403 Note: 3404 See `DMPlexGetConeRecursive()` 3405 3406 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3407 `DMPlexGetDepth()`, `IS`, `PetscSection` 3408 @*/ 3409 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3410 { 3411 PetscInt d, depth_; 3412 3413 PetscFunctionBegin; 3414 PetscCall(DMPlexGetDepth(dm, &depth_)); 3415 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3416 if (depth) *depth = 0; 3417 if (expandedPoints) { 3418 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3419 PetscCall(PetscFree(*expandedPoints)); 3420 } 3421 if (sections) { 3422 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3423 PetscCall(PetscFree(*sections)); 3424 } 3425 PetscFunctionReturn(PETSC_SUCCESS); 3426 } 3427 3428 /*@ 3429 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 3430 3431 Not Collective 3432 3433 Input Parameters: 3434 + dm - The `DMPLEX` 3435 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3436 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3437 3438 Level: beginner 3439 3440 Note: 3441 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3442 3443 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3444 @*/ 3445 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3446 { 3447 DM_Plex *mesh = (DM_Plex *)dm->data; 3448 PetscInt dof, off, c; 3449 3450 PetscFunctionBegin; 3451 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3452 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3453 if (dof) PetscAssertPointer(cone, 3); 3454 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3455 if (PetscDefined(USE_DEBUG)) { 3456 PetscInt pStart, pEnd; 3457 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3458 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3459 for (c = 0; c < dof; ++c) { 3460 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3461 mesh->cones[off + c] = cone[c]; 3462 } 3463 } else { 3464 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3465 } 3466 PetscFunctionReturn(PETSC_SUCCESS); 3467 } 3468 3469 /*@C 3470 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3471 3472 Not Collective 3473 3474 Input Parameters: 3475 + dm - The `DMPLEX` 3476 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3477 3478 Output Parameter: 3479 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3480 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3481 3482 Level: beginner 3483 3484 Note: 3485 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3486 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3487 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3488 with the identity. 3489 3490 Fortran Notes: 3491 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3492 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3493 3494 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3495 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3496 @*/ 3497 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3498 { 3499 DM_Plex *mesh = (DM_Plex *)dm->data; 3500 PetscInt off; 3501 3502 PetscFunctionBegin; 3503 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3504 if (PetscDefined(USE_DEBUG)) { 3505 PetscInt dof; 3506 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3507 if (dof) PetscAssertPointer(coneOrientation, 3); 3508 } 3509 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3510 3511 *coneOrientation = &mesh->coneOrientations[off]; 3512 PetscFunctionReturn(PETSC_SUCCESS); 3513 } 3514 3515 /*@ 3516 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3517 3518 Not Collective 3519 3520 Input Parameters: 3521 + dm - The `DMPLEX` 3522 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3523 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3524 3525 Level: beginner 3526 3527 Notes: 3528 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3529 3530 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3531 3532 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3533 @*/ 3534 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3535 { 3536 DM_Plex *mesh = (DM_Plex *)dm->data; 3537 PetscInt pStart, pEnd; 3538 PetscInt dof, off, c; 3539 3540 PetscFunctionBegin; 3541 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3542 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3543 if (dof) PetscAssertPointer(coneOrientation, 3); 3544 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3545 if (PetscDefined(USE_DEBUG)) { 3546 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3547 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3548 for (c = 0; c < dof; ++c) { 3549 PetscInt cdof, o = coneOrientation[c]; 3550 3551 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3552 PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof); 3553 mesh->coneOrientations[off + c] = o; 3554 } 3555 } else { 3556 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3557 } 3558 PetscFunctionReturn(PETSC_SUCCESS); 3559 } 3560 3561 /*@ 3562 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3563 3564 Not Collective 3565 3566 Input Parameters: 3567 + dm - The `DMPLEX` 3568 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3569 . conePos - The local index in the cone where the point should be put 3570 - conePoint - The mesh point to insert 3571 3572 Level: beginner 3573 3574 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3575 @*/ 3576 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3577 { 3578 DM_Plex *mesh = (DM_Plex *)dm->data; 3579 PetscInt pStart, pEnd; 3580 PetscInt dof, off; 3581 3582 PetscFunctionBegin; 3583 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3584 if (PetscDefined(USE_DEBUG)) { 3585 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3586 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3587 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3588 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3589 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3590 } 3591 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3592 mesh->cones[off + conePos] = conePoint; 3593 PetscFunctionReturn(PETSC_SUCCESS); 3594 } 3595 3596 /*@ 3597 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3598 3599 Not Collective 3600 3601 Input Parameters: 3602 + dm - The `DMPLEX` 3603 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3604 . conePos - The local index in the cone where the point should be put 3605 - coneOrientation - The point orientation to insert 3606 3607 Level: beginner 3608 3609 Note: 3610 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3611 3612 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3613 @*/ 3614 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3615 { 3616 DM_Plex *mesh = (DM_Plex *)dm->data; 3617 PetscInt pStart, pEnd; 3618 PetscInt dof, off; 3619 3620 PetscFunctionBegin; 3621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3622 if (PetscDefined(USE_DEBUG)) { 3623 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3624 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3625 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3626 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3627 } 3628 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3629 mesh->coneOrientations[off + conePos] = coneOrientation; 3630 PetscFunctionReturn(PETSC_SUCCESS); 3631 } 3632 3633 /*@C 3634 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3635 3636 Not collective 3637 3638 Input Parameters: 3639 + dm - The DMPlex 3640 - p - The point, which must lie in the chart set with DMPlexSetChart() 3641 3642 Output Parameters: 3643 + cone - An array of points which are on the in-edges for point `p` 3644 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3645 integer giving the prescription for cone traversal. 3646 3647 Level: beginner 3648 3649 Notes: 3650 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3651 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3652 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3653 with the identity. 3654 3655 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3656 3657 Fortran Notes: 3658 `cone` and `ornt` must be declared with 3659 .vb 3660 PetscInt, pointer :: cone(:) 3661 PetscInt, pointer :: ornt(:) 3662 .ve 3663 3664 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3665 @*/ 3666 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, PeOp const PetscInt *cone[], PeOp const PetscInt *ornt[]) 3667 { 3668 DM_Plex *mesh = (DM_Plex *)dm->data; 3669 3670 PetscFunctionBegin; 3671 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3672 if (mesh->tr) { 3673 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3674 } else { 3675 PetscInt off; 3676 if (PetscDefined(USE_DEBUG)) { 3677 PetscInt dof; 3678 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3679 if (dof) { 3680 if (cone) PetscAssertPointer(cone, 3); 3681 if (ornt) PetscAssertPointer(ornt, 4); 3682 } 3683 } 3684 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3685 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3686 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3687 } 3688 PetscFunctionReturn(PETSC_SUCCESS); 3689 } 3690 3691 /*@C 3692 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3693 3694 Not Collective 3695 3696 Input Parameters: 3697 + dm - The DMPlex 3698 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3699 . cone - An array of points which are on the in-edges for point p 3700 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3701 integer giving the prescription for cone traversal. 3702 3703 Level: beginner 3704 3705 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3706 @*/ 3707 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3708 { 3709 DM_Plex *mesh = (DM_Plex *)dm->data; 3710 3711 PetscFunctionBegin; 3712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3713 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3714 PetscFunctionReturn(PETSC_SUCCESS); 3715 } 3716 3717 /*@ 3718 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3719 3720 Not Collective 3721 3722 Input Parameters: 3723 + dm - The `DMPLEX` 3724 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3725 3726 Output Parameter: 3727 . size - The support size for point `p` 3728 3729 Level: beginner 3730 3731 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3732 @*/ 3733 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3734 { 3735 DM_Plex *mesh = (DM_Plex *)dm->data; 3736 3737 PetscFunctionBegin; 3738 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3739 PetscAssertPointer(size, 3); 3740 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3741 PetscFunctionReturn(PETSC_SUCCESS); 3742 } 3743 3744 /*@ 3745 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3746 3747 Not Collective 3748 3749 Input Parameters: 3750 + dm - The `DMPLEX` 3751 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3752 - size - The support size for point `p` 3753 3754 Level: beginner 3755 3756 Note: 3757 This should be called after `DMPlexSetChart()`. 3758 3759 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3760 @*/ 3761 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3762 { 3763 DM_Plex *mesh = (DM_Plex *)dm->data; 3764 3765 PetscFunctionBegin; 3766 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3767 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3768 PetscFunctionReturn(PETSC_SUCCESS); 3769 } 3770 3771 /*@C 3772 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3773 3774 Not Collective 3775 3776 Input Parameters: 3777 + dm - The `DMPLEX` 3778 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3779 3780 Output Parameter: 3781 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3782 3783 Level: beginner 3784 3785 Fortran Notes: 3786 `support` must be declared with 3787 .vb 3788 PetscInt, pointer :: support(:) 3789 .ve 3790 3791 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3792 `DMPlexRestoreSupport()` is not needed/available in C. 3793 3794 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3795 @*/ 3796 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3797 { 3798 DM_Plex *mesh = (DM_Plex *)dm->data; 3799 PetscInt off; 3800 3801 PetscFunctionBegin; 3802 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3803 PetscAssertPointer(support, 3); 3804 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3805 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3806 PetscFunctionReturn(PETSC_SUCCESS); 3807 } 3808 3809 /*@ 3810 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3811 3812 Not Collective 3813 3814 Input Parameters: 3815 + dm - The `DMPLEX` 3816 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3817 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3818 3819 Level: beginner 3820 3821 Note: 3822 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3823 3824 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3825 @*/ 3826 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3827 { 3828 DM_Plex *mesh = (DM_Plex *)dm->data; 3829 PetscInt pStart, pEnd; 3830 PetscInt dof, off, c; 3831 3832 PetscFunctionBegin; 3833 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3834 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3835 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3836 if (dof) PetscAssertPointer(support, 3); 3837 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3838 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3839 for (c = 0; c < dof; ++c) { 3840 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3841 mesh->supports[off + c] = support[c]; 3842 } 3843 PetscFunctionReturn(PETSC_SUCCESS); 3844 } 3845 3846 /*@ 3847 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3848 3849 Not Collective 3850 3851 Input Parameters: 3852 + dm - The `DMPLEX` 3853 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3854 . supportPos - The local index in the cone where the point should be put 3855 - supportPoint - The mesh point to insert 3856 3857 Level: beginner 3858 3859 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3860 @*/ 3861 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3862 { 3863 DM_Plex *mesh = (DM_Plex *)dm->data; 3864 PetscInt pStart, pEnd; 3865 PetscInt dof, off; 3866 3867 PetscFunctionBegin; 3868 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3869 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3870 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3871 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3872 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3873 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3874 PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3875 mesh->supports[off + supportPos] = supportPoint; 3876 PetscFunctionReturn(PETSC_SUCCESS); 3877 } 3878 3879 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3880 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3881 { 3882 switch (ct) { 3883 case DM_POLYTOPE_SEGMENT: 3884 if (o == -1) return -2; 3885 break; 3886 case DM_POLYTOPE_TRIANGLE: 3887 if (o == -3) return -1; 3888 if (o == -2) return -3; 3889 if (o == -1) return -2; 3890 break; 3891 case DM_POLYTOPE_QUADRILATERAL: 3892 if (o == -4) return -2; 3893 if (o == -3) return -1; 3894 if (o == -2) return -4; 3895 if (o == -1) return -3; 3896 break; 3897 default: 3898 return o; 3899 } 3900 return o; 3901 } 3902 3903 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3904 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3905 { 3906 switch (ct) { 3907 case DM_POLYTOPE_SEGMENT: 3908 if ((o == -2) || (o == 1)) return -1; 3909 if (o == -1) return 0; 3910 break; 3911 case DM_POLYTOPE_TRIANGLE: 3912 if (o == -3) return -2; 3913 if (o == -2) return -1; 3914 if (o == -1) return -3; 3915 break; 3916 case DM_POLYTOPE_QUADRILATERAL: 3917 if (o == -4) return -2; 3918 if (o == -3) return -1; 3919 if (o == -2) return -4; 3920 if (o == -1) return -3; 3921 break; 3922 default: 3923 return o; 3924 } 3925 return o; 3926 } 3927 3928 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3929 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3930 { 3931 PetscInt pStart, pEnd, p; 3932 3933 PetscFunctionBegin; 3934 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3935 for (p = pStart; p < pEnd; ++p) { 3936 const PetscInt *cone, *ornt; 3937 PetscInt coneSize, c; 3938 3939 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3940 PetscCall(DMPlexGetCone(dm, p, &cone)); 3941 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3942 for (c = 0; c < coneSize; ++c) { 3943 DMPolytopeType ct; 3944 const PetscInt o = ornt[c]; 3945 3946 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3947 switch (ct) { 3948 case DM_POLYTOPE_SEGMENT: 3949 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3950 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3951 break; 3952 case DM_POLYTOPE_TRIANGLE: 3953 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3954 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3955 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3956 break; 3957 case DM_POLYTOPE_QUADRILATERAL: 3958 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3959 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3960 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3961 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3962 break; 3963 default: 3964 break; 3965 } 3966 } 3967 } 3968 PetscFunctionReturn(PETSC_SUCCESS); 3969 } 3970 3971 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3972 { 3973 DM_Plex *mesh = (DM_Plex *)dm->data; 3974 3975 PetscFunctionBeginHot; 3976 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3977 if (useCone) { 3978 PetscCall(DMPlexGetConeSize(dm, p, size)); 3979 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3980 } else { 3981 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3982 PetscCall(DMPlexGetSupport(dm, p, arr)); 3983 } 3984 } else { 3985 if (useCone) { 3986 const PetscSection s = mesh->coneSection; 3987 const PetscInt ps = p - s->pStart; 3988 const PetscInt off = s->atlasOff[ps]; 3989 3990 *size = s->atlasDof[ps]; 3991 *arr = mesh->cones + off; 3992 *ornt = mesh->coneOrientations + off; 3993 } else { 3994 const PetscSection s = mesh->supportSection; 3995 const PetscInt ps = p - s->pStart; 3996 const PetscInt off = s->atlasOff[ps]; 3997 3998 *size = s->atlasDof[ps]; 3999 *arr = mesh->supports + off; 4000 } 4001 } 4002 PetscFunctionReturn(PETSC_SUCCESS); 4003 } 4004 4005 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 4006 { 4007 DM_Plex *mesh = (DM_Plex *)dm->data; 4008 4009 PetscFunctionBeginHot; 4010 if (PetscDefined(USE_DEBUG) || mesh->tr) { 4011 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 4012 } 4013 PetscFunctionReturn(PETSC_SUCCESS); 4014 } 4015 4016 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4017 { 4018 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4019 PetscInt *closure; 4020 const PetscInt *tmp = NULL, *tmpO = NULL; 4021 PetscInt off = 0, tmpSize, t; 4022 4023 PetscFunctionBeginHot; 4024 if (ornt) { 4025 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4026 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 4027 } 4028 if (*points) { 4029 closure = *points; 4030 } else { 4031 PetscInt maxConeSize, maxSupportSize; 4032 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4033 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 4034 } 4035 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4036 if (ct == DM_POLYTOPE_UNKNOWN) { 4037 closure[off++] = p; 4038 closure[off++] = 0; 4039 for (t = 0; t < tmpSize; ++t) { 4040 closure[off++] = tmp[t]; 4041 closure[off++] = tmpO ? tmpO[t] : 0; 4042 } 4043 } else { 4044 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 4045 4046 /* We assume that cells with a valid type have faces with a valid type */ 4047 closure[off++] = p; 4048 closure[off++] = ornt; 4049 for (t = 0; t < tmpSize; ++t) { 4050 DMPolytopeType ft; 4051 4052 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 4053 closure[off++] = tmp[arr[t]]; 4054 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 4055 } 4056 } 4057 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4058 if (numPoints) *numPoints = tmpSize + 1; 4059 if (points) *points = closure; 4060 PetscFunctionReturn(PETSC_SUCCESS); 4061 } 4062 4063 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 4064 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 4065 { 4066 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 4067 const PetscInt *cone, *ornt; 4068 PetscInt *pts, *closure = NULL; 4069 DMPolytopeType ft; 4070 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 4071 PetscInt dim, coneSize, c, d, clSize, cl; 4072 4073 PetscFunctionBeginHot; 4074 PetscCall(DMGetDimension(dm, &dim)); 4075 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4076 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4077 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4078 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4079 maxSize = PetscMax(coneSeries, supportSeries); 4080 if (*points) { 4081 pts = *points; 4082 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4083 c = 0; 4084 pts[c++] = point; 4085 pts[c++] = o; 4086 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4087 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4088 for (cl = 0; cl < clSize * 2; cl += 2) { 4089 pts[c++] = closure[cl]; 4090 pts[c++] = closure[cl + 1]; 4091 } 4092 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4093 for (cl = 0; cl < clSize * 2; cl += 2) { 4094 pts[c++] = closure[cl]; 4095 pts[c++] = closure[cl + 1]; 4096 } 4097 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4098 for (d = 2; d < coneSize; ++d) { 4099 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4100 pts[c++] = cone[arr[d * 2 + 0]]; 4101 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4102 } 4103 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4104 if (dim >= 3) { 4105 for (d = 2; d < coneSize; ++d) { 4106 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4107 const PetscInt *fcone, *fornt; 4108 PetscInt fconeSize, fc, i; 4109 4110 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4111 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4112 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4113 for (fc = 0; fc < fconeSize; ++fc) { 4114 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4115 const PetscInt co = farr[fc * 2 + 1]; 4116 4117 for (i = 0; i < c; i += 2) 4118 if (pts[i] == cp) break; 4119 if (i == c) { 4120 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4121 pts[c++] = cp; 4122 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4123 } 4124 } 4125 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4126 } 4127 } 4128 *numPoints = c / 2; 4129 *points = pts; 4130 PetscFunctionReturn(PETSC_SUCCESS); 4131 } 4132 4133 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4134 { 4135 DMPolytopeType ct; 4136 PetscInt *closure, *fifo; 4137 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4138 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4139 PetscInt depth, maxSize; 4140 4141 PetscFunctionBeginHot; 4142 PetscCall(DMPlexGetDepth(dm, &depth)); 4143 if (depth == 1) { 4144 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4145 PetscFunctionReturn(PETSC_SUCCESS); 4146 } 4147 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4148 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 4149 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4150 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4151 PetscFunctionReturn(PETSC_SUCCESS); 4152 } 4153 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4154 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4155 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4156 maxSize = PetscMax(coneSeries, supportSeries); 4157 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4158 if (*points) { 4159 closure = *points; 4160 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4161 closure[closureSize++] = p; 4162 closure[closureSize++] = ornt; 4163 fifo[fifoSize++] = p; 4164 fifo[fifoSize++] = ornt; 4165 fifo[fifoSize++] = ct; 4166 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4167 while (fifoSize - fifoStart) { 4168 const PetscInt q = fifo[fifoStart++]; 4169 const PetscInt o = fifo[fifoStart++]; 4170 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4171 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4172 const PetscInt *tmp, *tmpO = NULL; 4173 PetscInt tmpSize, t; 4174 4175 if (PetscDefined(USE_DEBUG)) { 4176 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4177 PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 4178 } 4179 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4180 for (t = 0; t < tmpSize; ++t) { 4181 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4182 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4183 const PetscInt cp = tmp[ip]; 4184 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4185 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4186 PetscInt c; 4187 4188 /* Check for duplicate */ 4189 for (c = 0; c < closureSize; c += 2) { 4190 if (closure[c] == cp) break; 4191 } 4192 if (c == closureSize) { 4193 closure[closureSize++] = cp; 4194 closure[closureSize++] = co; 4195 fifo[fifoSize++] = cp; 4196 fifo[fifoSize++] = co; 4197 fifo[fifoSize++] = ct; 4198 } 4199 } 4200 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4201 } 4202 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4203 if (numPoints) *numPoints = closureSize / 2; 4204 if (points) *points = closure; 4205 PetscFunctionReturn(PETSC_SUCCESS); 4206 } 4207 4208 /*@C 4209 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4210 4211 Not Collective 4212 4213 Input Parameters: 4214 + dm - The `DMPLEX` 4215 . p - The mesh point 4216 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4217 4218 Input/Output Parameter: 4219 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4220 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4221 otherwise the provided array is used to hold the values 4222 4223 Output Parameter: 4224 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4225 4226 Level: beginner 4227 4228 Note: 4229 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4230 4231 Fortran Notes: 4232 `points` must be declared with 4233 .vb 4234 PetscInt, pointer :: points(:) 4235 .ve 4236 and is always allocated by the function. 4237 4238 Pass `PETSC_NULL_INTEGER` for `numPoints` if it is not needed 4239 4240 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4241 @*/ 4242 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4243 { 4244 PetscFunctionBeginHot; 4245 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4246 if (numPoints) PetscAssertPointer(numPoints, 4); 4247 if (points) PetscAssertPointer(points, 5); 4248 if (PetscDefined(USE_DEBUG)) { 4249 PetscInt pStart, pEnd; 4250 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4251 PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 4252 } 4253 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4254 PetscFunctionReturn(PETSC_SUCCESS); 4255 } 4256 4257 /*@C 4258 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4259 4260 Not Collective 4261 4262 Input Parameters: 4263 + dm - The `DMPLEX` 4264 . p - The mesh point 4265 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4266 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4267 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4268 4269 Level: beginner 4270 4271 Note: 4272 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4273 4274 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4275 @*/ 4276 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4277 { 4278 PetscFunctionBeginHot; 4279 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4280 if (numPoints) *numPoints = 0; 4281 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4282 PetscFunctionReturn(PETSC_SUCCESS); 4283 } 4284 4285 /*@ 4286 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4287 4288 Not Collective 4289 4290 Input Parameter: 4291 . dm - The `DMPLEX` 4292 4293 Output Parameters: 4294 + maxConeSize - The maximum number of in-edges 4295 - maxSupportSize - The maximum number of out-edges 4296 4297 Level: beginner 4298 4299 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4300 @*/ 4301 PetscErrorCode DMPlexGetMaxSizes(DM dm, PeOp PetscInt *maxConeSize, PeOp PetscInt *maxSupportSize) 4302 { 4303 DM_Plex *mesh = (DM_Plex *)dm->data; 4304 4305 PetscFunctionBegin; 4306 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4307 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4308 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4309 PetscFunctionReturn(PETSC_SUCCESS); 4310 } 4311 4312 PetscErrorCode DMSetUp_Plex(DM dm) 4313 { 4314 DM_Plex *mesh = (DM_Plex *)dm->data; 4315 PetscInt size, maxSupportSize; 4316 4317 PetscFunctionBegin; 4318 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4319 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4320 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4321 PetscCall(PetscMalloc1(size, &mesh->cones)); 4322 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4323 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4324 if (maxSupportSize) { 4325 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4326 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4327 PetscCall(PetscMalloc1(size, &mesh->supports)); 4328 } 4329 PetscFunctionReturn(PETSC_SUCCESS); 4330 } 4331 4332 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4333 { 4334 PetscFunctionBegin; 4335 if (subdm) PetscCall(DMClone(dm, subdm)); 4336 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4337 if (subdm) (*subdm)->useNatural = dm->useNatural; 4338 if (dm->useNatural && dm->sfMigration) { 4339 PetscSF sfNatural; 4340 4341 (*subdm)->sfMigration = dm->sfMigration; 4342 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4343 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4344 (*subdm)->sfNatural = sfNatural; 4345 } 4346 PetscFunctionReturn(PETSC_SUCCESS); 4347 } 4348 4349 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4350 { 4351 PetscInt i = 0; 4352 4353 PetscFunctionBegin; 4354 PetscCall(DMClone(dms[0], superdm)); 4355 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4356 (*superdm)->useNatural = PETSC_FALSE; 4357 for (i = 0; i < len; i++) { 4358 if (dms[i]->useNatural && dms[i]->sfMigration) { 4359 PetscSF sfNatural; 4360 4361 (*superdm)->sfMigration = dms[i]->sfMigration; 4362 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4363 (*superdm)->useNatural = PETSC_TRUE; 4364 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4365 (*superdm)->sfNatural = sfNatural; 4366 break; 4367 } 4368 } 4369 PetscFunctionReturn(PETSC_SUCCESS); 4370 } 4371 4372 /*@ 4373 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4374 4375 Not Collective 4376 4377 Input Parameter: 4378 . dm - The `DMPLEX` 4379 4380 Level: beginner 4381 4382 Note: 4383 This should be called after all calls to `DMPlexSetCone()` 4384 4385 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4386 @*/ 4387 PetscErrorCode DMPlexSymmetrize(DM dm) 4388 { 4389 DM_Plex *mesh = (DM_Plex *)dm->data; 4390 PetscInt *offsets; 4391 PetscInt supportSize; 4392 PetscInt pStart, pEnd, p; 4393 4394 PetscFunctionBegin; 4395 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4396 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4397 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4398 /* Calculate support sizes */ 4399 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4400 for (p = pStart; p < pEnd; ++p) { 4401 PetscInt dof, off, c; 4402 4403 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4404 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4405 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4406 } 4407 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4408 /* Calculate supports */ 4409 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4410 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4411 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4412 for (p = pStart; p < pEnd; ++p) { 4413 PetscInt dof, off, c; 4414 4415 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4416 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4417 for (c = off; c < off + dof; ++c) { 4418 const PetscInt q = mesh->cones[c]; 4419 PetscInt offS; 4420 4421 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4422 4423 mesh->supports[offS + offsets[q]] = p; 4424 ++offsets[q]; 4425 } 4426 } 4427 PetscCall(PetscFree(offsets)); 4428 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4429 PetscFunctionReturn(PETSC_SUCCESS); 4430 } 4431 4432 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4433 { 4434 IS stratumIS; 4435 4436 PetscFunctionBegin; 4437 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4438 if (PetscDefined(USE_DEBUG)) { 4439 PetscInt qStart, qEnd, numLevels, level; 4440 PetscBool overlap = PETSC_FALSE; 4441 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4442 for (level = 0; level < numLevels; level++) { 4443 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4444 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4445 overlap = PETSC_TRUE; 4446 break; 4447 } 4448 } 4449 PetscCheck(!overlap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd); 4450 } 4451 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4452 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4453 PetscCall(ISDestroy(&stratumIS)); 4454 PetscFunctionReturn(PETSC_SUCCESS); 4455 } 4456 4457 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4458 { 4459 PetscInt *pMin, *pMax; 4460 PetscInt pStart, pEnd; 4461 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4462 4463 PetscFunctionBegin; 4464 { 4465 DMLabel label2; 4466 4467 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4468 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4469 } 4470 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4471 for (PetscInt p = pStart; p < pEnd; ++p) { 4472 DMPolytopeType ct; 4473 4474 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4475 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4476 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4477 } 4478 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4479 for (PetscInt d = dmin; d <= dmax; ++d) { 4480 pMin[d] = PETSC_INT_MAX; 4481 pMax[d] = PETSC_INT_MIN; 4482 } 4483 for (PetscInt p = pStart; p < pEnd; ++p) { 4484 DMPolytopeType ct; 4485 PetscInt d; 4486 4487 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4488 d = DMPolytopeTypeGetDim(ct); 4489 pMin[d] = PetscMin(p, pMin[d]); 4490 pMax[d] = PetscMax(p, pMax[d]); 4491 } 4492 for (PetscInt d = dmin; d <= dmax; ++d) { 4493 if (pMin[d] > pMax[d]) continue; 4494 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4495 } 4496 PetscCall(PetscFree2(pMin, pMax)); 4497 PetscFunctionReturn(PETSC_SUCCESS); 4498 } 4499 4500 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4501 { 4502 PetscInt pStart, pEnd; 4503 PetscInt numRoots = 0, numLeaves = 0; 4504 4505 PetscFunctionBegin; 4506 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4507 { 4508 /* Initialize roots and count leaves */ 4509 PetscInt sMin = PETSC_INT_MAX; 4510 PetscInt sMax = PETSC_INT_MIN; 4511 PetscInt coneSize, supportSize; 4512 4513 for (PetscInt p = pStart; p < pEnd; ++p) { 4514 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4515 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4516 if (!coneSize && supportSize) { 4517 sMin = PetscMin(p, sMin); 4518 sMax = PetscMax(p, sMax); 4519 ++numRoots; 4520 } else if (!supportSize && coneSize) { 4521 ++numLeaves; 4522 } else if (!supportSize && !coneSize) { 4523 /* Isolated points */ 4524 sMin = PetscMin(p, sMin); 4525 sMax = PetscMax(p, sMax); 4526 } 4527 } 4528 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4529 } 4530 4531 if (numRoots + numLeaves == (pEnd - pStart)) { 4532 PetscInt sMin = PETSC_INT_MAX; 4533 PetscInt sMax = PETSC_INT_MIN; 4534 PetscInt coneSize, supportSize; 4535 4536 for (PetscInt p = pStart; p < pEnd; ++p) { 4537 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4538 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4539 if (!supportSize && coneSize) { 4540 sMin = PetscMin(p, sMin); 4541 sMax = PetscMax(p, sMax); 4542 } 4543 } 4544 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4545 } else { 4546 PetscInt level = 0; 4547 PetscInt qStart, qEnd; 4548 4549 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4550 while (qEnd > qStart) { 4551 PetscInt sMin = PETSC_INT_MAX; 4552 PetscInt sMax = PETSC_INT_MIN; 4553 4554 for (PetscInt q = qStart; q < qEnd; ++q) { 4555 const PetscInt *support; 4556 PetscInt supportSize; 4557 4558 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4559 PetscCall(DMPlexGetSupport(dm, q, &support)); 4560 for (PetscInt s = 0; s < supportSize; ++s) { 4561 sMin = PetscMin(support[s], sMin); 4562 sMax = PetscMax(support[s], sMax); 4563 } 4564 } 4565 PetscCall(DMLabelGetNumValues(label, &level)); 4566 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4567 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4568 } 4569 } 4570 PetscFunctionReturn(PETSC_SUCCESS); 4571 } 4572 4573 /*@ 4574 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4575 4576 Collective 4577 4578 Input Parameter: 4579 . dm - The `DMPLEX` 4580 4581 Level: beginner 4582 4583 Notes: 4584 The strata group all points of the same grade, and this function calculates the strata. This 4585 grade can be seen as the height (or depth) of the point in the DAG. 4586 4587 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4588 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4589 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4590 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4591 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4592 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4593 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4594 4595 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4596 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4597 we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose 4598 to interpolate only that one (e0), so that 4599 .vb 4600 cone(c0) = {e0, v2} 4601 cone(e0) = {v0, v1} 4602 .ve 4603 If `DMPlexStratify()` is run on this mesh, it will give depths 4604 .vb 4605 depth 0 = {v0, v1, v2} 4606 depth 1 = {e0, c0} 4607 .ve 4608 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4609 4610 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4611 4612 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4613 @*/ 4614 PetscErrorCode DMPlexStratify(DM dm) 4615 { 4616 DM_Plex *mesh = (DM_Plex *)dm->data; 4617 DMLabel label; 4618 PetscBool flg = PETSC_FALSE; 4619 4620 PetscFunctionBegin; 4621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4622 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4623 4624 // Create depth label 4625 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4626 PetscCall(DMCreateLabel(dm, "depth")); 4627 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4628 4629 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4630 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4631 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4632 4633 { /* just in case there is an empty process */ 4634 PetscInt numValues, maxValues = 0, v; 4635 4636 PetscCall(DMLabelGetNumValues(label, &numValues)); 4637 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4638 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4639 } 4640 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4641 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4642 PetscFunctionReturn(PETSC_SUCCESS); 4643 } 4644 4645 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4646 { 4647 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4648 PetscInt dim, depth, pheight, coneSize; 4649 PetscBool preferTensor; 4650 4651 PetscFunctionBeginHot; 4652 PetscCall(DMGetDimension(dm, &dim)); 4653 PetscCall(DMPlexGetDepth(dm, &depth)); 4654 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4655 PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor)); 4656 pheight = depth - pdepth; 4657 if (depth <= 1) { 4658 switch (pdepth) { 4659 case 0: 4660 ct = DM_POLYTOPE_POINT; 4661 break; 4662 case 1: 4663 switch (coneSize) { 4664 case 2: 4665 ct = DM_POLYTOPE_SEGMENT; 4666 break; 4667 case 3: 4668 ct = DM_POLYTOPE_TRIANGLE; 4669 break; 4670 case 4: 4671 switch (dim) { 4672 case 2: 4673 ct = DM_POLYTOPE_QUADRILATERAL; 4674 break; 4675 case 3: 4676 ct = DM_POLYTOPE_TETRAHEDRON; 4677 break; 4678 default: 4679 break; 4680 } 4681 break; 4682 case 5: 4683 ct = DM_POLYTOPE_PYRAMID; 4684 break; 4685 case 6: 4686 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4687 break; 4688 case 8: 4689 ct = DM_POLYTOPE_HEXAHEDRON; 4690 break; 4691 default: 4692 break; 4693 } 4694 } 4695 } else { 4696 if (pdepth == 0) { 4697 ct = DM_POLYTOPE_POINT; 4698 } else if (pheight == 0) { 4699 switch (dim) { 4700 case 1: 4701 switch (coneSize) { 4702 case 2: 4703 ct = DM_POLYTOPE_SEGMENT; 4704 break; 4705 default: 4706 break; 4707 } 4708 break; 4709 case 2: 4710 switch (coneSize) { 4711 case 3: 4712 ct = DM_POLYTOPE_TRIANGLE; 4713 break; 4714 case 4: 4715 ct = DM_POLYTOPE_QUADRILATERAL; 4716 break; 4717 default: 4718 break; 4719 } 4720 break; 4721 case 3: 4722 switch (coneSize) { 4723 case 4: 4724 ct = DM_POLYTOPE_TETRAHEDRON; 4725 break; 4726 case 5: { 4727 const PetscInt *cone; 4728 PetscInt faceConeSize; 4729 4730 PetscCall(DMPlexGetCone(dm, p, &cone)); 4731 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4732 switch (faceConeSize) { 4733 case 3: 4734 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4735 break; 4736 case 4: 4737 ct = DM_POLYTOPE_PYRAMID; 4738 break; 4739 } 4740 } break; 4741 case 6: 4742 ct = DM_POLYTOPE_HEXAHEDRON; 4743 break; 4744 default: 4745 break; 4746 } 4747 break; 4748 default: 4749 break; 4750 } 4751 } else if (pheight > 0) { 4752 switch (coneSize) { 4753 case 2: 4754 ct = DM_POLYTOPE_SEGMENT; 4755 break; 4756 case 3: 4757 ct = DM_POLYTOPE_TRIANGLE; 4758 break; 4759 case 4: 4760 ct = DM_POLYTOPE_QUADRILATERAL; 4761 break; 4762 default: 4763 break; 4764 } 4765 } 4766 } 4767 *pt = ct; 4768 PetscFunctionReturn(PETSC_SUCCESS); 4769 } 4770 4771 /*@ 4772 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4773 4774 Collective 4775 4776 Input Parameter: 4777 . dm - The `DMPLEX` 4778 4779 Level: developer 4780 4781 Note: 4782 This function is normally called automatically when a cell type is requested. It creates an 4783 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4784 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4785 4786 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4787 4788 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4789 @*/ 4790 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4791 { 4792 DM_Plex *mesh; 4793 DMLabel ctLabel; 4794 PetscInt pStart, pEnd, p; 4795 4796 PetscFunctionBegin; 4797 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4798 mesh = (DM_Plex *)dm->data; 4799 PetscCall(DMCreateLabel(dm, "celltype")); 4800 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4801 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4802 PetscCall(PetscFree(mesh->cellTypes)); 4803 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4804 for (p = pStart; p < pEnd; ++p) { 4805 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4806 PetscInt pdepth; 4807 4808 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4809 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4810 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]); 4811 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4812 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4813 } 4814 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4815 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4816 PetscFunctionReturn(PETSC_SUCCESS); 4817 } 4818 4819 /*@C 4820 DMPlexGetJoin - Get an array for the join of the set of points 4821 4822 Not Collective 4823 4824 Input Parameters: 4825 + dm - The `DMPLEX` object 4826 . numPoints - The number of input points for the join 4827 - points - The input points 4828 4829 Output Parameters: 4830 + numCoveredPoints - The number of points in the join 4831 - coveredPoints - The points in the join 4832 4833 Level: intermediate 4834 4835 Note: 4836 Currently, this is restricted to a single level join 4837 4838 Fortran Notes: 4839 `converedPoints` must be declared with 4840 .vb 4841 PetscInt, pointer :: coveredPints(:) 4842 .ve 4843 4844 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4845 @*/ 4846 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4847 { 4848 DM_Plex *mesh = (DM_Plex *)dm->data; 4849 PetscInt *join[2]; 4850 PetscInt joinSize, i = 0; 4851 PetscInt dof, off, p, c, m; 4852 PetscInt maxSupportSize; 4853 4854 PetscFunctionBegin; 4855 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4856 PetscAssertPointer(points, 3); 4857 PetscAssertPointer(numCoveredPoints, 4); 4858 PetscAssertPointer(coveredPoints, 5); 4859 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4860 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4861 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4862 /* Copy in support of first point */ 4863 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4864 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4865 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4866 /* Check each successive support */ 4867 for (p = 1; p < numPoints; ++p) { 4868 PetscInt newJoinSize = 0; 4869 4870 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4871 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4872 for (c = 0; c < dof; ++c) { 4873 const PetscInt point = mesh->supports[off + c]; 4874 4875 for (m = 0; m < joinSize; ++m) { 4876 if (point == join[i][m]) { 4877 join[1 - i][newJoinSize++] = point; 4878 break; 4879 } 4880 } 4881 } 4882 joinSize = newJoinSize; 4883 i = 1 - i; 4884 } 4885 *numCoveredPoints = joinSize; 4886 *coveredPoints = join[i]; 4887 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4888 PetscFunctionReturn(PETSC_SUCCESS); 4889 } 4890 4891 /*@C 4892 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4893 4894 Not Collective 4895 4896 Input Parameters: 4897 + dm - The `DMPLEX` object 4898 . numPoints - The number of input points for the join 4899 - points - The input points 4900 4901 Output Parameters: 4902 + numCoveredPoints - The number of points in the join 4903 - coveredPoints - The points in the join 4904 4905 Level: intermediate 4906 4907 Fortran Notes: 4908 `converedPoints` must be declared with 4909 .vb 4910 PetscInt, pointer :: coveredPoints(:) 4911 .ve 4912 4913 Pass `PETSC_NULL_INTEGER` for `numCoveredPoints` if it is not needed 4914 4915 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4916 @*/ 4917 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4918 { 4919 PetscFunctionBegin; 4920 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4921 if (points) PetscAssertPointer(points, 3); 4922 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4923 PetscAssertPointer(coveredPoints, 5); 4924 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4925 if (numCoveredPoints) *numCoveredPoints = 0; 4926 PetscFunctionReturn(PETSC_SUCCESS); 4927 } 4928 4929 /*@C 4930 DMPlexGetFullJoin - Get an array for the join of the set of points 4931 4932 Not Collective 4933 4934 Input Parameters: 4935 + dm - The `DMPLEX` object 4936 . numPoints - The number of input points for the join 4937 - points - The input points, its length is `numPoints` 4938 4939 Output Parameters: 4940 + numCoveredPoints - The number of points in the join 4941 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4942 4943 Level: intermediate 4944 4945 Fortran Notes: 4946 .vb 4947 PetscInt, pointer :: coveredPints(:) 4948 .ve 4949 4950 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4951 @*/ 4952 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4953 { 4954 PetscInt *offsets, **closures; 4955 PetscInt *join[2]; 4956 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4957 PetscInt p, d, c, m, ms; 4958 4959 PetscFunctionBegin; 4960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4961 PetscAssertPointer(points, 3); 4962 PetscAssertPointer(numCoveredPoints, 4); 4963 PetscAssertPointer(coveredPoints, 5); 4964 4965 PetscCall(DMPlexGetDepth(dm, &depth)); 4966 PetscCall(PetscCalloc1(numPoints, &closures)); 4967 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4968 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4969 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4970 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4971 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4972 4973 for (p = 0; p < numPoints; ++p) { 4974 PetscInt closureSize; 4975 4976 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4977 4978 offsets[p * (depth + 2) + 0] = 0; 4979 for (d = 0; d < depth + 1; ++d) { 4980 PetscInt pStart, pEnd, i; 4981 4982 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4983 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4984 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4985 offsets[p * (depth + 2) + d + 1] = i; 4986 break; 4987 } 4988 } 4989 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4990 } 4991 PetscCheck(offsets[p * (depth + 2) + depth + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (depth + 2) + depth + 1], closureSize); 4992 } 4993 for (d = 0; d < depth + 1; ++d) { 4994 PetscInt dof; 4995 4996 /* Copy in support of first point */ 4997 dof = offsets[d + 1] - offsets[d]; 4998 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4999 /* Check each successive cone */ 5000 for (p = 1; p < numPoints && joinSize; ++p) { 5001 PetscInt newJoinSize = 0; 5002 5003 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 5004 for (c = 0; c < dof; ++c) { 5005 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 5006 5007 for (m = 0; m < joinSize; ++m) { 5008 if (point == join[i][m]) { 5009 join[1 - i][newJoinSize++] = point; 5010 break; 5011 } 5012 } 5013 } 5014 joinSize = newJoinSize; 5015 i = 1 - i; 5016 } 5017 if (joinSize) break; 5018 } 5019 *numCoveredPoints = joinSize; 5020 *coveredPoints = join[i]; 5021 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 5022 PetscCall(PetscFree(closures)); 5023 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 5024 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 5025 PetscFunctionReturn(PETSC_SUCCESS); 5026 } 5027 5028 /*@C 5029 DMPlexGetMeet - Get an array for the meet of the set of points 5030 5031 Not Collective 5032 5033 Input Parameters: 5034 + dm - The `DMPLEX` object 5035 . numPoints - The number of input points for the meet 5036 - points - The input points, of length `numPoints` 5037 5038 Output Parameters: 5039 + numCoveringPoints - The number of points in the meet 5040 - coveringPoints - The points in the meet, of length `numCoveringPoints` 5041 5042 Level: intermediate 5043 5044 Note: 5045 Currently, this is restricted to a single level meet 5046 5047 Fortran Note: 5048 `coveringPoints` must be declared with 5049 .vb 5050 PetscInt, pointer :: coveringPoints(:) 5051 .ve 5052 5053 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5054 @*/ 5055 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 5056 { 5057 DM_Plex *mesh = (DM_Plex *)dm->data; 5058 PetscInt *meet[2]; 5059 PetscInt meetSize, i = 0; 5060 PetscInt dof, off, p, c, m; 5061 PetscInt maxConeSize; 5062 5063 PetscFunctionBegin; 5064 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5065 PetscAssertPointer(points, 3); 5066 PetscAssertPointer(numCoveringPoints, 4); 5067 PetscAssertPointer(coveringPoints, 5); 5068 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 5069 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 5070 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 5071 /* Copy in cone of first point */ 5072 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 5073 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 5074 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5075 /* Check each successive cone */ 5076 for (p = 1; p < numPoints; ++p) { 5077 PetscInt newMeetSize = 0; 5078 5079 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5080 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5081 for (c = 0; c < dof; ++c) { 5082 const PetscInt point = mesh->cones[off + c]; 5083 5084 for (m = 0; m < meetSize; ++m) { 5085 if (point == meet[i][m]) { 5086 meet[1 - i][newMeetSize++] = point; 5087 break; 5088 } 5089 } 5090 } 5091 meetSize = newMeetSize; 5092 i = 1 - i; 5093 } 5094 *numCoveringPoints = meetSize; 5095 *coveringPoints = meet[i]; 5096 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5097 PetscFunctionReturn(PETSC_SUCCESS); 5098 } 5099 5100 /*@C 5101 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5102 5103 Not Collective 5104 5105 Input Parameters: 5106 + dm - The `DMPLEX` object 5107 . numPoints - The number of input points for the meet 5108 - points - The input points 5109 5110 Output Parameters: 5111 + numCoveredPoints - The number of points in the meet 5112 - coveredPoints - The points in the meet 5113 5114 Level: intermediate 5115 5116 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5117 @*/ 5118 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5119 { 5120 PetscFunctionBegin; 5121 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5122 if (points) PetscAssertPointer(points, 3); 5123 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5124 PetscAssertPointer(coveredPoints, 5); 5125 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5126 if (numCoveredPoints) *numCoveredPoints = 0; 5127 PetscFunctionReturn(PETSC_SUCCESS); 5128 } 5129 5130 /*@C 5131 DMPlexGetFullMeet - Get an array for the meet of the set of points 5132 5133 Not Collective 5134 5135 Input Parameters: 5136 + dm - The `DMPLEX` object 5137 . numPoints - The number of input points for the meet 5138 - points - The input points, of length `numPoints` 5139 5140 Output Parameters: 5141 + numCoveredPoints - The number of points in the meet 5142 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5143 5144 Level: intermediate 5145 5146 Fortran Notes: 5147 `coveredPoints` must be declared with 5148 .vb 5149 PetscInt, pointer :: coveredPoints(:) 5150 .ve 5151 5152 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5153 @*/ 5154 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5155 { 5156 PetscInt *offsets, **closures; 5157 PetscInt *meet[2]; 5158 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5159 PetscInt p, h, c, m, mc; 5160 5161 PetscFunctionBegin; 5162 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5163 PetscAssertPointer(points, 3); 5164 PetscAssertPointer(numCoveredPoints, 4); 5165 PetscAssertPointer(coveredPoints, 5); 5166 5167 PetscCall(DMPlexGetDepth(dm, &height)); 5168 PetscCall(PetscMalloc1(numPoints, &closures)); 5169 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5170 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5171 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5172 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5173 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5174 5175 for (p = 0; p < numPoints; ++p) { 5176 PetscInt closureSize; 5177 5178 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5179 5180 offsets[p * (height + 2) + 0] = 0; 5181 for (h = 0; h < height + 1; ++h) { 5182 PetscInt pStart, pEnd, i; 5183 5184 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5185 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5186 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5187 offsets[p * (height + 2) + h + 1] = i; 5188 break; 5189 } 5190 } 5191 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5192 } 5193 PetscCheck(offsets[p * (height + 2) + height + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (height + 2) + height + 1], closureSize); 5194 } 5195 for (h = 0; h < height + 1; ++h) { 5196 PetscInt dof; 5197 5198 /* Copy in cone of first point */ 5199 dof = offsets[h + 1] - offsets[h]; 5200 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5201 /* Check each successive cone */ 5202 for (p = 1; p < numPoints && meetSize; ++p) { 5203 PetscInt newMeetSize = 0; 5204 5205 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5206 for (c = 0; c < dof; ++c) { 5207 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5208 5209 for (m = 0; m < meetSize; ++m) { 5210 if (point == meet[i][m]) { 5211 meet[1 - i][newMeetSize++] = point; 5212 break; 5213 } 5214 } 5215 } 5216 meetSize = newMeetSize; 5217 i = 1 - i; 5218 } 5219 if (meetSize) break; 5220 } 5221 *numCoveredPoints = meetSize; 5222 *coveredPoints = meet[i]; 5223 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5224 PetscCall(PetscFree(closures)); 5225 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5226 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5227 PetscFunctionReturn(PETSC_SUCCESS); 5228 } 5229 5230 /*@ 5231 DMPlexEqual - Determine if two `DM` have the same topology 5232 5233 Not Collective 5234 5235 Input Parameters: 5236 + dmA - A `DMPLEX` object 5237 - dmB - A `DMPLEX` object 5238 5239 Output Parameter: 5240 . equal - `PETSC_TRUE` if the topologies are identical 5241 5242 Level: intermediate 5243 5244 Note: 5245 We are not solving graph isomorphism, so we do not permute. 5246 5247 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5248 @*/ 5249 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5250 { 5251 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5252 5253 PetscFunctionBegin; 5254 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5255 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5256 PetscAssertPointer(equal, 3); 5257 5258 *equal = PETSC_FALSE; 5259 PetscCall(DMPlexGetDepth(dmA, &depth)); 5260 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5261 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5262 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5263 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5264 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5265 for (p = pStart; p < pEnd; ++p) { 5266 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5267 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5268 5269 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5270 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5271 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5272 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5273 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5274 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5275 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5276 for (c = 0; c < coneSize; ++c) { 5277 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5278 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5279 } 5280 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5281 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5282 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5283 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5284 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5285 for (s = 0; s < supportSize; ++s) { 5286 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5287 } 5288 } 5289 *equal = PETSC_TRUE; 5290 PetscFunctionReturn(PETSC_SUCCESS); 5291 } 5292 5293 /*@ 5294 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5295 5296 Not Collective 5297 5298 Input Parameters: 5299 + dm - The `DMPLEX` 5300 . cellDim - The cell dimension 5301 - numCorners - The number of vertices on a cell 5302 5303 Output Parameter: 5304 . numFaceVertices - The number of vertices on a face 5305 5306 Level: developer 5307 5308 Note: 5309 Of course this can only work for a restricted set of symmetric shapes 5310 5311 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5312 @*/ 5313 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5314 { 5315 MPI_Comm comm; 5316 5317 PetscFunctionBegin; 5318 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5319 PetscAssertPointer(numFaceVertices, 4); 5320 switch (cellDim) { 5321 case 0: 5322 *numFaceVertices = 0; 5323 break; 5324 case 1: 5325 *numFaceVertices = 1; 5326 break; 5327 case 2: 5328 switch (numCorners) { 5329 case 3: /* triangle */ 5330 *numFaceVertices = 2; /* Edge has 2 vertices */ 5331 break; 5332 case 4: /* quadrilateral */ 5333 *numFaceVertices = 2; /* Edge has 2 vertices */ 5334 break; 5335 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5336 *numFaceVertices = 3; /* Edge has 3 vertices */ 5337 break; 5338 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5339 *numFaceVertices = 3; /* Edge has 3 vertices */ 5340 break; 5341 default: 5342 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5343 } 5344 break; 5345 case 3: 5346 switch (numCorners) { 5347 case 4: /* tetradehdron */ 5348 *numFaceVertices = 3; /* Face has 3 vertices */ 5349 break; 5350 case 6: /* tet cohesive cells */ 5351 *numFaceVertices = 4; /* Face has 4 vertices */ 5352 break; 5353 case 8: /* hexahedron */ 5354 *numFaceVertices = 4; /* Face has 4 vertices */ 5355 break; 5356 case 9: /* tet cohesive Lagrange cells */ 5357 *numFaceVertices = 6; /* Face has 6 vertices */ 5358 break; 5359 case 10: /* quadratic tetrahedron */ 5360 *numFaceVertices = 6; /* Face has 6 vertices */ 5361 break; 5362 case 12: /* hex cohesive Lagrange cells */ 5363 *numFaceVertices = 6; /* Face has 6 vertices */ 5364 break; 5365 case 18: /* quadratic tet cohesive Lagrange cells */ 5366 *numFaceVertices = 6; /* Face has 6 vertices */ 5367 break; 5368 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5369 *numFaceVertices = 9; /* Face has 9 vertices */ 5370 break; 5371 default: 5372 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5373 } 5374 break; 5375 default: 5376 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5377 } 5378 PetscFunctionReturn(PETSC_SUCCESS); 5379 } 5380 5381 /*@ 5382 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5383 5384 Not Collective 5385 5386 Input Parameter: 5387 . dm - The `DMPLEX` object 5388 5389 Output Parameter: 5390 . depthLabel - The `DMLabel` recording point depth 5391 5392 Level: developer 5393 5394 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5395 @*/ 5396 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5397 { 5398 PetscFunctionBegin; 5399 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5400 PetscAssertPointer(depthLabel, 2); 5401 *depthLabel = dm->depthLabel; 5402 PetscFunctionReturn(PETSC_SUCCESS); 5403 } 5404 5405 /*@ 5406 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5407 5408 Not Collective 5409 5410 Input Parameter: 5411 . dm - The `DMPLEX` object 5412 5413 Output Parameter: 5414 . depth - The number of strata (breadth first levels) in the DAG 5415 5416 Level: developer 5417 5418 Notes: 5419 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5420 5421 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5422 5423 An empty mesh gives -1. 5424 5425 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5426 @*/ 5427 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5428 { 5429 DM_Plex *mesh = (DM_Plex *)dm->data; 5430 DMLabel label; 5431 PetscInt d = -1; 5432 5433 PetscFunctionBegin; 5434 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5435 PetscAssertPointer(depth, 2); 5436 if (mesh->tr) { 5437 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5438 } else { 5439 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5440 // Allow missing depths 5441 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5442 *depth = d; 5443 } 5444 PetscFunctionReturn(PETSC_SUCCESS); 5445 } 5446 5447 /*@ 5448 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5449 5450 Not Collective 5451 5452 Input Parameters: 5453 + dm - The `DMPLEX` object 5454 - depth - The requested depth 5455 5456 Output Parameters: 5457 + start - The first point at this `depth` 5458 - end - One beyond the last point at this `depth` 5459 5460 Level: developer 5461 5462 Notes: 5463 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5464 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5465 higher dimension, e.g., "edges". 5466 5467 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5468 @*/ 5469 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PeOp PetscInt *start, PeOp PetscInt *end) 5470 { 5471 DM_Plex *mesh = (DM_Plex *)dm->data; 5472 DMLabel label; 5473 PetscInt pStart, pEnd; 5474 5475 PetscFunctionBegin; 5476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5477 if (start) { 5478 PetscAssertPointer(start, 3); 5479 *start = 0; 5480 } 5481 if (end) { 5482 PetscAssertPointer(end, 4); 5483 *end = 0; 5484 } 5485 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5486 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5487 if (depth < 0) { 5488 if (start) *start = pStart; 5489 if (end) *end = pEnd; 5490 PetscFunctionReturn(PETSC_SUCCESS); 5491 } 5492 if (mesh->tr) { 5493 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5494 } else { 5495 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5496 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5497 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5498 } 5499 PetscFunctionReturn(PETSC_SUCCESS); 5500 } 5501 5502 /*@ 5503 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5504 5505 Not Collective 5506 5507 Input Parameters: 5508 + dm - The `DMPLEX` object 5509 - height - The requested height 5510 5511 Output Parameters: 5512 + start - The first point at this `height` 5513 - end - One beyond the last point at this `height` 5514 5515 Level: developer 5516 5517 Notes: 5518 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5519 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5520 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5521 5522 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5523 @*/ 5524 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PeOp PetscInt *start, PeOp PetscInt *end) 5525 { 5526 DMLabel label; 5527 PetscInt depth, pStart, pEnd; 5528 5529 PetscFunctionBegin; 5530 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5531 if (start) { 5532 PetscAssertPointer(start, 3); 5533 *start = 0; 5534 } 5535 if (end) { 5536 PetscAssertPointer(end, 4); 5537 *end = 0; 5538 } 5539 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5540 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5541 if (height < 0) { 5542 if (start) *start = pStart; 5543 if (end) *end = pEnd; 5544 PetscFunctionReturn(PETSC_SUCCESS); 5545 } 5546 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5547 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5548 else PetscCall(DMGetDimension(dm, &depth)); 5549 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5550 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5551 PetscFunctionReturn(PETSC_SUCCESS); 5552 } 5553 5554 /*@ 5555 DMPlexGetPointDepth - Get the `depth` of a given point 5556 5557 Not Collective 5558 5559 Input Parameters: 5560 + dm - The `DMPLEX` object 5561 - point - The point 5562 5563 Output Parameter: 5564 . depth - The depth of the `point` 5565 5566 Level: intermediate 5567 5568 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5569 @*/ 5570 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5571 { 5572 PetscFunctionBegin; 5573 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5574 PetscAssertPointer(depth, 3); 5575 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5576 PetscFunctionReturn(PETSC_SUCCESS); 5577 } 5578 5579 /*@ 5580 DMPlexGetPointHeight - Get the `height` of a given point 5581 5582 Not Collective 5583 5584 Input Parameters: 5585 + dm - The `DMPLEX` object 5586 - point - The point 5587 5588 Output Parameter: 5589 . height - The height of the `point` 5590 5591 Level: intermediate 5592 5593 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5594 @*/ 5595 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5596 { 5597 PetscInt n, pDepth; 5598 5599 PetscFunctionBegin; 5600 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5601 PetscAssertPointer(height, 3); 5602 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5603 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5604 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5605 PetscFunctionReturn(PETSC_SUCCESS); 5606 } 5607 5608 /*@ 5609 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5610 5611 Not Collective 5612 5613 Input Parameter: 5614 . dm - The `DMPLEX` object 5615 5616 Output Parameter: 5617 . celltypeLabel - The `DMLabel` recording cell polytope type 5618 5619 Level: developer 5620 5621 Note: 5622 This function will trigger automatica computation of cell types. This can be disabled by calling 5623 `DMCreateLabel`(dm, "celltype") beforehand. 5624 5625 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5626 @*/ 5627 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5628 { 5629 PetscFunctionBegin; 5630 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5631 PetscAssertPointer(celltypeLabel, 2); 5632 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5633 *celltypeLabel = dm->celltypeLabel; 5634 PetscFunctionReturn(PETSC_SUCCESS); 5635 } 5636 5637 /*@ 5638 DMPlexGetCellType - Get the polytope type of a given cell 5639 5640 Not Collective 5641 5642 Input Parameters: 5643 + dm - The `DMPLEX` object 5644 - cell - The cell 5645 5646 Output Parameter: 5647 . celltype - The polytope type of the cell 5648 5649 Level: intermediate 5650 5651 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5652 @*/ 5653 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5654 { 5655 DM_Plex *mesh = (DM_Plex *)dm->data; 5656 DMLabel label; 5657 PetscInt ct; 5658 5659 PetscFunctionBegin; 5660 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5661 PetscAssertPointer(celltype, 3); 5662 if (mesh->tr) { 5663 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5664 } else { 5665 PetscInt pStart, pEnd; 5666 5667 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5668 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5669 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5670 if (pEnd <= pStart) { 5671 *celltype = DM_POLYTOPE_UNKNOWN; 5672 PetscFunctionReturn(PETSC_SUCCESS); 5673 } 5674 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5675 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5676 for (PetscInt p = pStart; p < pEnd; p++) { 5677 PetscCall(DMLabelGetValue(label, p, &ct)); 5678 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5679 } 5680 } 5681 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5682 if (PetscDefined(USE_DEBUG)) { 5683 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5684 PetscCall(DMLabelGetValue(label, cell, &ct)); 5685 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5686 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5687 } 5688 } 5689 PetscFunctionReturn(PETSC_SUCCESS); 5690 } 5691 5692 /*@ 5693 DMPlexSetCellType - Set the polytope type of a given cell 5694 5695 Not Collective 5696 5697 Input Parameters: 5698 + dm - The `DMPLEX` object 5699 . cell - The cell 5700 - celltype - The polytope type of the cell 5701 5702 Level: advanced 5703 5704 Note: 5705 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5706 is executed. This function will override the computed type. However, if automatic classification will not succeed 5707 and a user wants to manually specify all types, the classification must be disabled by calling 5708 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5709 5710 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5711 @*/ 5712 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5713 { 5714 DM_Plex *mesh = (DM_Plex *)dm->data; 5715 DMLabel label; 5716 PetscInt pStart, pEnd; 5717 5718 PetscFunctionBegin; 5719 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5720 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5721 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5722 PetscCall(DMLabelSetValue(label, cell, celltype)); 5723 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5724 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5725 PetscFunctionReturn(PETSC_SUCCESS); 5726 } 5727 5728 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5729 { 5730 PetscSection section; 5731 PetscInt maxHeight; 5732 const char *prefix; 5733 5734 PetscFunctionBegin; 5735 PetscCall(DMClone(dm, cdm)); 5736 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5737 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5738 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5739 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5740 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5741 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5742 PetscCall(DMSetLocalSection(*cdm, section)); 5743 PetscCall(PetscSectionDestroy(§ion)); 5744 5745 PetscCall(DMSetNumFields(*cdm, 1)); 5746 PetscCall(DMCreateDS(*cdm)); 5747 (*cdm)->cloneOpts = PETSC_TRUE; 5748 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5749 PetscFunctionReturn(PETSC_SUCCESS); 5750 } 5751 5752 PetscErrorCode DMCreateCellCoordinateDM_Plex(DM dm, DM *cdm) 5753 { 5754 DM cgcdm; 5755 PetscSection section; 5756 const char *prefix; 5757 5758 PetscFunctionBegin; 5759 PetscCall(DMGetCoordinateDM(dm, &cgcdm)); 5760 PetscCall(DMClone(cgcdm, cdm)); 5761 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5762 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5763 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cellcdm_")); 5764 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5765 PetscCall(DMSetLocalSection(*cdm, section)); 5766 PetscCall(PetscSectionDestroy(§ion)); 5767 PetscCall(DMSetNumFields(*cdm, 1)); 5768 PetscCall(DMCreateDS(*cdm)); 5769 (*cdm)->cloneOpts = PETSC_TRUE; 5770 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5771 PetscFunctionReturn(PETSC_SUCCESS); 5772 } 5773 5774 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5775 { 5776 Vec coordsLocal, cellCoordsLocal; 5777 DM coordsDM, cellCoordsDM; 5778 5779 PetscFunctionBegin; 5780 *field = NULL; 5781 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5782 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5783 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5784 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5785 if (coordsLocal && coordsDM) { 5786 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5787 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5788 } 5789 PetscFunctionReturn(PETSC_SUCCESS); 5790 } 5791 5792 /*@ 5793 DMPlexGetConeSection - Return a section which describes the layout of cone data 5794 5795 Not Collective 5796 5797 Input Parameter: 5798 . dm - The `DMPLEX` object 5799 5800 Output Parameter: 5801 . section - The `PetscSection` object 5802 5803 Level: developer 5804 5805 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5806 @*/ 5807 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5808 { 5809 DM_Plex *mesh = (DM_Plex *)dm->data; 5810 5811 PetscFunctionBegin; 5812 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5813 if (section) *section = mesh->coneSection; 5814 PetscFunctionReturn(PETSC_SUCCESS); 5815 } 5816 5817 /*@ 5818 DMPlexGetSupportSection - Return a section which describes the layout of support data 5819 5820 Not Collective 5821 5822 Input Parameter: 5823 . dm - The `DMPLEX` object 5824 5825 Output Parameter: 5826 . section - The `PetscSection` object 5827 5828 Level: developer 5829 5830 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5831 @*/ 5832 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5833 { 5834 DM_Plex *mesh = (DM_Plex *)dm->data; 5835 5836 PetscFunctionBegin; 5837 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5838 if (section) *section = mesh->supportSection; 5839 PetscFunctionReturn(PETSC_SUCCESS); 5840 } 5841 5842 /*@C 5843 DMPlexGetCones - Return cone data 5844 5845 Not Collective 5846 5847 Input Parameter: 5848 . dm - The `DMPLEX` object 5849 5850 Output Parameter: 5851 . cones - The cone for each point 5852 5853 Level: developer 5854 5855 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5856 @*/ 5857 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5858 { 5859 DM_Plex *mesh = (DM_Plex *)dm->data; 5860 5861 PetscFunctionBegin; 5862 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5863 if (cones) *cones = mesh->cones; 5864 PetscFunctionReturn(PETSC_SUCCESS); 5865 } 5866 5867 /*@C 5868 DMPlexGetConeOrientations - Return cone orientation data 5869 5870 Not Collective 5871 5872 Input Parameter: 5873 . dm - The `DMPLEX` object 5874 5875 Output Parameter: 5876 . coneOrientations - The array of cone orientations for all points 5877 5878 Level: developer 5879 5880 Notes: 5881 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5882 as returned by `DMPlexGetConeOrientation()`. 5883 5884 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5885 5886 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5887 @*/ 5888 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5889 { 5890 DM_Plex *mesh = (DM_Plex *)dm->data; 5891 5892 PetscFunctionBegin; 5893 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5894 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5895 PetscFunctionReturn(PETSC_SUCCESS); 5896 } 5897 5898 /* FEM Support */ 5899 5900 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5901 { 5902 PetscInt depth; 5903 5904 PetscFunctionBegin; 5905 PetscCall(DMPlexGetDepth(plex, &depth)); 5906 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5907 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5908 PetscFunctionReturn(PETSC_SUCCESS); 5909 } 5910 5911 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5912 { 5913 PetscInt depth; 5914 5915 PetscFunctionBegin; 5916 PetscCall(DMPlexGetDepth(plex, &depth)); 5917 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5918 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5919 PetscFunctionReturn(PETSC_SUCCESS); 5920 } 5921 5922 /* 5923 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5924 representing a line in the section. 5925 */ 5926 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5927 { 5928 PetscObject obj; 5929 PetscClassId id; 5930 PetscFE fe = NULL; 5931 5932 PetscFunctionBeginHot; 5933 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5934 PetscCall(DMGetField(dm, field, NULL, &obj)); 5935 PetscCall(PetscObjectGetClassId(obj, &id)); 5936 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5937 5938 if (!fe) { 5939 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5940 /* An order k SEM disc has k-1 dofs on an edge */ 5941 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5942 *k = *k / *Nc + 1; 5943 } else { 5944 PetscInt dual_space_size, dim; 5945 PetscDualSpace dsp; 5946 5947 PetscCall(DMGetDimension(dm, &dim)); 5948 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5949 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5950 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5951 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5952 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5953 } 5954 PetscFunctionReturn(PETSC_SUCCESS); 5955 } 5956 5957 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5958 { 5959 PetscFunctionBeginHot; 5960 if (tensor) { 5961 *dof = PetscPowInt(k + 1, dim); 5962 } else { 5963 switch (dim) { 5964 case 1: 5965 *dof = k + 1; 5966 break; 5967 case 2: 5968 *dof = ((k + 1) * (k + 2)) / 2; 5969 break; 5970 case 3: 5971 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5972 break; 5973 default: 5974 *dof = 0; 5975 } 5976 } 5977 PetscFunctionReturn(PETSC_SUCCESS); 5978 } 5979 5980 /*@ 5981 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5982 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5983 section provided (or the section of the `DM`). 5984 5985 Input Parameters: 5986 + dm - The `DM` 5987 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5988 - section - The `PetscSection` to reorder, or `NULL` for the default section 5989 5990 Example: 5991 A typical interpolated single-quad mesh might order points as 5992 .vb 5993 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5994 5995 v4 -- e6 -- v3 5996 | | 5997 e7 c0 e8 5998 | | 5999 v1 -- e5 -- v2 6000 .ve 6001 6002 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 6003 dofs in the order of points, e.g., 6004 .vb 6005 c0 -> [0,1,2,3] 6006 v1 -> [4] 6007 ... 6008 e5 -> [8, 9] 6009 .ve 6010 6011 which corresponds to the dofs 6012 .vb 6013 6 10 11 7 6014 13 2 3 15 6015 12 0 1 14 6016 4 8 9 5 6017 .ve 6018 6019 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 6020 .vb 6021 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 6022 .ve 6023 6024 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 6025 .vb 6026 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 6027 .ve 6028 6029 Level: developer 6030 6031 Notes: 6032 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 6033 degree of the basis. 6034 6035 This is required to run with libCEED. 6036 6037 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 6038 @*/ 6039 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 6040 { 6041 DMLabel label; 6042 PetscInt dim, depth = -1, eStart = -1, Nf; 6043 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 6044 6045 PetscFunctionBegin; 6046 PetscCall(DMGetDimension(dm, &dim)); 6047 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 6048 if (point < 0) { 6049 PetscInt sStart, sEnd; 6050 6051 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6052 point = sEnd - sStart ? sStart : point; 6053 } 6054 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6055 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6056 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6057 if (depth == 1) { 6058 eStart = point; 6059 } else if (depth == dim) { 6060 const PetscInt *cone; 6061 6062 PetscCall(DMPlexGetCone(dm, point, &cone)); 6063 if (dim == 2) eStart = cone[0]; 6064 else if (dim == 3) { 6065 const PetscInt *cone2; 6066 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6067 eStart = cone2[0]; 6068 } 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); 6069 } 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); 6070 6071 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6072 for (PetscInt d = 1; d <= dim; d++) { 6073 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6074 PetscInt *perm; 6075 6076 for (f = 0; f < Nf; ++f) { 6077 PetscInt dof; 6078 6079 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6080 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6081 if (!continuous && d < dim) continue; 6082 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6083 size += dof * Nc; 6084 } 6085 PetscCall(PetscMalloc1(size, &perm)); 6086 for (f = 0; f < Nf; ++f) { 6087 switch (d) { 6088 case 1: 6089 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6090 if (!continuous && d < dim) continue; 6091 /* 6092 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6093 We want [ vtx0; edge of length k-1; vtx1 ] 6094 */ 6095 if (continuous) { 6096 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6097 for (i = 0; i < k - 1; i++) 6098 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6099 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6100 foffset = offset; 6101 } else { 6102 PetscInt dof; 6103 6104 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6105 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6106 foffset = offset; 6107 } 6108 break; 6109 case 2: 6110 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6111 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6112 if (!continuous && d < dim) continue; 6113 /* The SEM order is 6114 6115 v_lb, {e_b}, v_rb, 6116 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6117 v_lt, reverse {e_t}, v_rt 6118 */ 6119 if (continuous) { 6120 const PetscInt of = 0; 6121 const PetscInt oeb = of + PetscSqr(k - 1); 6122 const PetscInt oer = oeb + (k - 1); 6123 const PetscInt oet = oer + (k - 1); 6124 const PetscInt oel = oet + (k - 1); 6125 const PetscInt ovlb = oel + (k - 1); 6126 const PetscInt ovrb = ovlb + 1; 6127 const PetscInt ovrt = ovrb + 1; 6128 const PetscInt ovlt = ovrt + 1; 6129 PetscInt o; 6130 6131 /* bottom */ 6132 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6133 for (o = oeb; o < oer; ++o) 6134 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6135 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6136 /* middle */ 6137 for (i = 0; i < k - 1; ++i) { 6138 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6139 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6140 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6141 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6142 } 6143 /* top */ 6144 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6145 for (o = oel - 1; o >= oet; --o) 6146 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6147 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6148 foffset = offset; 6149 } else { 6150 PetscInt dof; 6151 6152 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6153 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6154 foffset = offset; 6155 } 6156 break; 6157 case 3: 6158 /* The original hex closure is 6159 6160 {c, 6161 f_b, f_t, f_f, f_b, f_r, f_l, 6162 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6163 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6164 */ 6165 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6166 if (!continuous && d < dim) continue; 6167 /* The SEM order is 6168 Bottom Slice 6169 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6170 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6171 v_blb, {e_bb}, v_brb, 6172 6173 Middle Slice (j) 6174 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6175 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6176 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6177 6178 Top Slice 6179 v_tlf, {e_tf}, v_trf, 6180 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6181 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6182 */ 6183 if (continuous) { 6184 const PetscInt oc = 0; 6185 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6186 const PetscInt oft = ofb + PetscSqr(k - 1); 6187 const PetscInt off = oft + PetscSqr(k - 1); 6188 const PetscInt ofk = off + PetscSqr(k - 1); 6189 const PetscInt ofr = ofk + PetscSqr(k - 1); 6190 const PetscInt ofl = ofr + PetscSqr(k - 1); 6191 const PetscInt oebl = ofl + PetscSqr(k - 1); 6192 const PetscInt oebb = oebl + (k - 1); 6193 const PetscInt oebr = oebb + (k - 1); 6194 const PetscInt oebf = oebr + (k - 1); 6195 const PetscInt oetf = oebf + (k - 1); 6196 const PetscInt oetr = oetf + (k - 1); 6197 const PetscInt oetb = oetr + (k - 1); 6198 const PetscInt oetl = oetb + (k - 1); 6199 const PetscInt oerf = oetl + (k - 1); 6200 const PetscInt oelf = oerf + (k - 1); 6201 const PetscInt oelb = oelf + (k - 1); 6202 const PetscInt oerb = oelb + (k - 1); 6203 const PetscInt ovblf = oerb + (k - 1); 6204 const PetscInt ovblb = ovblf + 1; 6205 const PetscInt ovbrb = ovblb + 1; 6206 const PetscInt ovbrf = ovbrb + 1; 6207 const PetscInt ovtlf = ovbrf + 1; 6208 const PetscInt ovtrf = ovtlf + 1; 6209 const PetscInt ovtrb = ovtrf + 1; 6210 const PetscInt ovtlb = ovtrb + 1; 6211 PetscInt o, n; 6212 6213 /* Bottom Slice */ 6214 /* bottom */ 6215 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6216 for (o = oetf - 1; o >= oebf; --o) 6217 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6218 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6219 /* middle */ 6220 for (i = 0; i < k - 1; ++i) { 6221 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6222 for (n = 0; n < k - 1; ++n) { 6223 o = ofb + n * (k - 1) + i; 6224 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6225 } 6226 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6227 } 6228 /* top */ 6229 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6230 for (o = oebb; o < oebr; ++o) 6231 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6232 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6233 6234 /* Middle Slice */ 6235 for (j = 0; j < k - 1; ++j) { 6236 /* bottom */ 6237 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6238 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6239 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6240 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6241 /* middle */ 6242 for (i = 0; i < k - 1; ++i) { 6243 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6244 for (n = 0; n < k - 1; ++n) 6245 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6246 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6247 } 6248 /* top */ 6249 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6250 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6251 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6252 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6253 } 6254 6255 /* Top Slice */ 6256 /* bottom */ 6257 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6258 for (o = oetf; o < oetr; ++o) 6259 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6260 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6261 /* middle */ 6262 for (i = 0; i < k - 1; ++i) { 6263 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6264 for (n = 0; n < k - 1; ++n) 6265 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6266 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6267 } 6268 /* top */ 6269 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6270 for (o = oetl - 1; o >= oetb; --o) 6271 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6272 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6273 6274 foffset = offset; 6275 } else { 6276 PetscInt dof; 6277 6278 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6279 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6280 foffset = offset; 6281 } 6282 break; 6283 default: 6284 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6285 } 6286 } 6287 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6288 /* Check permutation */ 6289 { 6290 PetscInt *check; 6291 6292 PetscCall(PetscMalloc1(size, &check)); 6293 for (i = 0; i < size; ++i) { 6294 check[i] = -1; 6295 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6296 } 6297 for (i = 0; i < size; ++i) check[perm[i]] = i; 6298 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6299 PetscCall(PetscFree(check)); 6300 } 6301 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6302 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6303 PetscInt *loc_perm; 6304 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6305 for (PetscInt i = 0; i < size; i++) { 6306 loc_perm[i] = perm[i]; 6307 loc_perm[size + i] = size + perm[i]; 6308 } 6309 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6310 } 6311 } 6312 PetscFunctionReturn(PETSC_SUCCESS); 6313 } 6314 6315 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6316 { 6317 PetscDS prob; 6318 PetscInt depth, Nf, h; 6319 DMLabel label; 6320 6321 PetscFunctionBeginHot; 6322 PetscCall(DMGetDS(dm, &prob)); 6323 Nf = prob->Nf; 6324 label = dm->depthLabel; 6325 *dspace = NULL; 6326 if (field < Nf) { 6327 PetscObject disc = prob->disc[field]; 6328 6329 if (disc->classid == PETSCFE_CLASSID) { 6330 PetscDualSpace dsp; 6331 6332 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6333 PetscCall(DMLabelGetNumValues(label, &depth)); 6334 PetscCall(DMLabelGetValue(label, point, &h)); 6335 h = depth - 1 - h; 6336 if (h) { 6337 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6338 } else { 6339 *dspace = dsp; 6340 } 6341 } 6342 } 6343 PetscFunctionReturn(PETSC_SUCCESS); 6344 } 6345 6346 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6347 { 6348 PetscScalar *array; 6349 const PetscScalar *vArray; 6350 const PetscInt *cone, *coneO; 6351 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6352 6353 PetscFunctionBeginHot; 6354 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6355 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6356 PetscCall(DMPlexGetCone(dm, point, &cone)); 6357 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6358 if (!values || !*values) { 6359 if ((point >= pStart) && (point < pEnd)) { 6360 PetscInt dof; 6361 6362 PetscCall(PetscSectionGetDof(section, point, &dof)); 6363 size += dof; 6364 } 6365 for (p = 0; p < numPoints; ++p) { 6366 const PetscInt cp = cone[p]; 6367 PetscInt dof; 6368 6369 if ((cp < pStart) || (cp >= pEnd)) continue; 6370 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6371 size += dof; 6372 } 6373 if (!values) { 6374 if (csize) *csize = size; 6375 PetscFunctionReturn(PETSC_SUCCESS); 6376 } 6377 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6378 } else { 6379 array = *values; 6380 } 6381 size = 0; 6382 PetscCall(VecGetArrayRead(v, &vArray)); 6383 if ((point >= pStart) && (point < pEnd)) { 6384 PetscInt dof, off, d; 6385 const PetscScalar *varr; 6386 6387 PetscCall(PetscSectionGetDof(section, point, &dof)); 6388 PetscCall(PetscSectionGetOffset(section, point, &off)); 6389 varr = PetscSafePointerPlusOffset(vArray, off); 6390 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6391 size += dof; 6392 } 6393 for (p = 0; p < numPoints; ++p) { 6394 const PetscInt cp = cone[p]; 6395 PetscInt o = coneO[p]; 6396 PetscInt dof, off, d; 6397 const PetscScalar *varr; 6398 6399 if ((cp < pStart) || (cp >= pEnd)) continue; 6400 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6401 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6402 varr = PetscSafePointerPlusOffset(vArray, off); 6403 if (o >= 0) { 6404 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6405 } else { 6406 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6407 } 6408 size += dof; 6409 } 6410 PetscCall(VecRestoreArrayRead(v, &vArray)); 6411 if (!*values) { 6412 if (csize) *csize = size; 6413 *values = array; 6414 } else { 6415 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6416 *csize = size; 6417 } 6418 PetscFunctionReturn(PETSC_SUCCESS); 6419 } 6420 6421 /* Compress out points not in the section */ 6422 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6423 { 6424 const PetscInt np = *numPoints; 6425 PetscInt pStart, pEnd, p, q; 6426 6427 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6428 for (p = 0, q = 0; p < np; ++p) { 6429 const PetscInt r = points[p * 2]; 6430 if ((r >= pStart) && (r < pEnd)) { 6431 points[q * 2] = r; 6432 points[q * 2 + 1] = points[p * 2 + 1]; 6433 ++q; 6434 } 6435 } 6436 *numPoints = q; 6437 return PETSC_SUCCESS; 6438 } 6439 6440 /* Compressed closure does not apply closure permutation */ 6441 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6442 { 6443 const PetscInt *cla = NULL; 6444 PetscInt np, *pts = NULL; 6445 6446 PetscFunctionBeginHot; 6447 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6448 if (!ornt && *clPoints) { 6449 PetscInt dof, off; 6450 6451 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6452 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6453 PetscCall(ISGetIndices(*clPoints, &cla)); 6454 np = dof / 2; 6455 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6456 } else { 6457 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6458 PetscCall(CompressPoints_Private(section, &np, pts)); 6459 } 6460 *numPoints = np; 6461 *points = pts; 6462 *clp = cla; 6463 PetscFunctionReturn(PETSC_SUCCESS); 6464 } 6465 6466 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6467 { 6468 PetscFunctionBeginHot; 6469 if (!*clPoints) { 6470 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6471 } else { 6472 PetscCall(ISRestoreIndices(*clPoints, clp)); 6473 } 6474 *numPoints = 0; 6475 *points = NULL; 6476 *clSec = NULL; 6477 *clPoints = NULL; 6478 *clp = NULL; 6479 PetscFunctionReturn(PETSC_SUCCESS); 6480 } 6481 6482 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6483 { 6484 PetscInt offset = 0, p; 6485 const PetscInt **perms = NULL; 6486 const PetscScalar **flips = NULL; 6487 6488 PetscFunctionBeginHot; 6489 *size = 0; 6490 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6491 for (p = 0; p < numPoints; p++) { 6492 const PetscInt point = points[2 * p]; 6493 const PetscInt *perm = perms ? perms[p] : NULL; 6494 const PetscScalar *flip = flips ? flips[p] : NULL; 6495 PetscInt dof, off, d; 6496 const PetscScalar *varr; 6497 6498 PetscCall(PetscSectionGetDof(section, point, &dof)); 6499 PetscCall(PetscSectionGetOffset(section, point, &off)); 6500 varr = PetscSafePointerPlusOffset(vArray, off); 6501 if (clperm) { 6502 if (perm) { 6503 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6504 } else { 6505 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6506 } 6507 if (flip) { 6508 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6509 } 6510 } else { 6511 if (perm) { 6512 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6513 } else { 6514 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6515 } 6516 if (flip) { 6517 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6518 } 6519 } 6520 offset += dof; 6521 } 6522 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6523 *size = offset; 6524 PetscFunctionReturn(PETSC_SUCCESS); 6525 } 6526 6527 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[]) 6528 { 6529 PetscInt offset = 0, f; 6530 6531 PetscFunctionBeginHot; 6532 *size = 0; 6533 for (f = 0; f < numFields; ++f) { 6534 PetscInt p; 6535 const PetscInt **perms = NULL; 6536 const PetscScalar **flips = NULL; 6537 6538 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6539 for (p = 0; p < numPoints; p++) { 6540 const PetscInt point = points[2 * p]; 6541 PetscInt fdof, foff, b; 6542 const PetscScalar *varr; 6543 const PetscInt *perm = perms ? perms[p] : NULL; 6544 const PetscScalar *flip = flips ? flips[p] : NULL; 6545 6546 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6547 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6548 varr = &vArray[foff]; 6549 if (clperm) { 6550 if (perm) { 6551 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6552 } else { 6553 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6554 } 6555 if (flip) { 6556 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6557 } 6558 } else { 6559 if (perm) { 6560 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6561 } else { 6562 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6563 } 6564 if (flip) { 6565 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6566 } 6567 } 6568 offset += fdof; 6569 } 6570 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6571 } 6572 *size = offset; 6573 PetscFunctionReturn(PETSC_SUCCESS); 6574 } 6575 6576 /*@C 6577 DMPlexVecGetOrientedClosure - Get an array of the values on the closure of 'point' with a given orientation, optionally applying the closure permutation. 6578 6579 Not collective 6580 6581 Input Parameters: 6582 + dm - The `DM` 6583 . section - The section describing the layout in `v`, or `NULL` to use the default section 6584 . useClPerm - Flag for whether the provided closure permutation should be applied to the values 6585 . v - The local vector 6586 . point - The point in the `DM` 6587 - ornt - The orientation of the cell, an integer giving the prescription for cone traversal. Typically, this will be 0. 6588 6589 Input/Output Parameters: 6590 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6591 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6592 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6593 6594 Level: advanced 6595 6596 Notes: 6597 `DMPlexVecGetOrientedClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6598 calling function. This is because `DMPlexVecGetOrientedClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6599 assembly function, and a user may already have allocated storage for this operation. 6600 6601 Fortran Notes: 6602 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6603 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6604 6605 `values` must be declared with 6606 .vb 6607 PetscScalar,dimension(:),pointer :: values 6608 .ve 6609 and it will be allocated internally by PETSc to hold the values returned 6610 6611 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexGetCellCoordinates()`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()` 6612 @*/ 6613 PetscErrorCode DMPlexVecGetOrientedClosure(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6614 { 6615 PetscSection clSection; 6616 IS clPoints; 6617 PetscInt *points = NULL; 6618 const PetscInt *clp, *perm = NULL; 6619 PetscInt depth, numFields, numPoints, asize; 6620 6621 PetscFunctionBeginHot; 6622 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6623 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6624 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6625 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6626 PetscCall(DMPlexGetDepth(dm, &depth)); 6627 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6628 if (depth == 1 && numFields < 2) { 6629 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6630 PetscFunctionReturn(PETSC_SUCCESS); 6631 } 6632 /* Get points */ 6633 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6634 /* Get sizes */ 6635 asize = 0; 6636 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6637 PetscInt dof; 6638 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6639 asize += dof; 6640 } 6641 if (values) { 6642 const PetscScalar *vArray; 6643 PetscInt size; 6644 6645 if (*values) { 6646 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); 6647 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6648 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6649 PetscCall(VecGetArrayRead(v, &vArray)); 6650 /* Get values */ 6651 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6652 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6653 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6654 /* Cleanup array */ 6655 PetscCall(VecRestoreArrayRead(v, &vArray)); 6656 } 6657 if (csize) *csize = asize; 6658 /* Cleanup points */ 6659 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6660 PetscFunctionReturn(PETSC_SUCCESS); 6661 } 6662 6663 /*@C 6664 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6665 6666 Not collective 6667 6668 Input Parameters: 6669 + dm - The `DM` 6670 . section - The section describing the layout in `v`, or `NULL` to use the default section 6671 . v - The local vector 6672 - point - The point in the `DM` 6673 6674 Input/Output Parameters: 6675 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6676 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6677 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6678 6679 Level: intermediate 6680 6681 Notes: 6682 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6683 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6684 assembly function, and a user may already have allocated storage for this operation. 6685 6686 A typical use could be 6687 .vb 6688 values = NULL; 6689 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6690 for (cl = 0; cl < clSize; ++cl) { 6691 <Compute on closure> 6692 } 6693 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6694 .ve 6695 or 6696 .vb 6697 PetscMalloc1(clMaxSize, &values); 6698 for (p = pStart; p < pEnd; ++p) { 6699 clSize = clMaxSize; 6700 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6701 for (cl = 0; cl < clSize; ++cl) { 6702 <Compute on closure> 6703 } 6704 } 6705 PetscFree(values); 6706 .ve 6707 6708 Fortran Notes: 6709 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6710 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6711 6712 `values` must be declared with 6713 .vb 6714 PetscScalar,dimension(:),pointer :: values 6715 .ve 6716 and it will be allocated internally by PETSc to hold the values returned 6717 6718 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6719 @*/ 6720 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6721 { 6722 PetscFunctionBeginHot; 6723 PetscCall(DMPlexVecGetOrientedClosure(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6724 PetscFunctionReturn(PETSC_SUCCESS); 6725 } 6726 6727 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6728 { 6729 DMLabel depthLabel; 6730 PetscSection clSection; 6731 IS clPoints; 6732 PetscScalar *array; 6733 const PetscScalar *vArray; 6734 PetscInt *points = NULL; 6735 const PetscInt *clp, *perm = NULL; 6736 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6737 6738 PetscFunctionBeginHot; 6739 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6740 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6741 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6742 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6743 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6744 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6745 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6746 if (mdepth == 1 && numFields < 2) { 6747 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6748 PetscFunctionReturn(PETSC_SUCCESS); 6749 } 6750 /* Get points */ 6751 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6752 for (clsize = 0, p = 0; p < Np; p++) { 6753 PetscInt dof; 6754 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6755 clsize += dof; 6756 } 6757 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6758 /* Filter points */ 6759 for (p = 0; p < numPoints * 2; p += 2) { 6760 PetscInt dep; 6761 6762 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6763 if (dep != depth) continue; 6764 points[Np * 2 + 0] = points[p]; 6765 points[Np * 2 + 1] = points[p + 1]; 6766 ++Np; 6767 } 6768 /* Get array */ 6769 if (!values || !*values) { 6770 PetscInt asize = 0, dof; 6771 6772 for (p = 0; p < Np * 2; p += 2) { 6773 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6774 asize += dof; 6775 } 6776 if (!values) { 6777 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6778 if (csize) *csize = asize; 6779 PetscFunctionReturn(PETSC_SUCCESS); 6780 } 6781 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6782 } else { 6783 array = *values; 6784 } 6785 PetscCall(VecGetArrayRead(v, &vArray)); 6786 /* Get values */ 6787 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6788 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6789 /* Cleanup points */ 6790 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6791 /* Cleanup array */ 6792 PetscCall(VecRestoreArrayRead(v, &vArray)); 6793 if (!*values) { 6794 if (csize) *csize = size; 6795 *values = array; 6796 } else { 6797 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6798 *csize = size; 6799 } 6800 PetscFunctionReturn(PETSC_SUCCESS); 6801 } 6802 6803 /*@C 6804 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6805 6806 Not collective 6807 6808 Input Parameters: 6809 + dm - The `DM` 6810 . section - The section describing the layout in `v`, or `NULL` to use the default section 6811 . v - The local vector 6812 . point - The point in the `DM` 6813 . csize - The number of values in the closure, or `NULL` 6814 - values - The array of values 6815 6816 Level: intermediate 6817 6818 Note: 6819 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6820 6821 Fortran Note: 6822 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6823 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6824 6825 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6826 @*/ 6827 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6828 { 6829 PetscInt size = 0; 6830 6831 PetscFunctionBegin; 6832 /* Should work without recalculating size */ 6833 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6834 *values = NULL; 6835 PetscFunctionReturn(PETSC_SUCCESS); 6836 } 6837 6838 static inline void add(PetscScalar *x, PetscScalar y) 6839 { 6840 *x += y; 6841 } 6842 static inline void insert(PetscScalar *x, PetscScalar y) 6843 { 6844 *x = y; 6845 } 6846 6847 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[]) 6848 { 6849 PetscInt cdof; /* The number of constraints on this point */ 6850 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6851 PetscScalar *a; 6852 PetscInt off, cind = 0, k; 6853 6854 PetscFunctionBegin; 6855 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6856 PetscCall(PetscSectionGetOffset(section, point, &off)); 6857 a = &array[off]; 6858 if (!cdof || setBC) { 6859 if (clperm) { 6860 if (perm) { 6861 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6862 } else { 6863 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6864 } 6865 } else { 6866 if (perm) { 6867 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6868 } else { 6869 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6870 } 6871 } 6872 } else { 6873 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6874 if (clperm) { 6875 if (perm) { 6876 for (k = 0; k < dof; ++k) { 6877 if ((cind < cdof) && (k == cdofs[cind])) { 6878 ++cind; 6879 continue; 6880 } 6881 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6882 } 6883 } else { 6884 for (k = 0; k < dof; ++k) { 6885 if ((cind < cdof) && (k == cdofs[cind])) { 6886 ++cind; 6887 continue; 6888 } 6889 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6890 } 6891 } 6892 } else { 6893 if (perm) { 6894 for (k = 0; k < dof; ++k) { 6895 if ((cind < cdof) && (k == cdofs[cind])) { 6896 ++cind; 6897 continue; 6898 } 6899 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6900 } 6901 } else { 6902 for (k = 0; k < dof; ++k) { 6903 if ((cind < cdof) && (k == cdofs[cind])) { 6904 ++cind; 6905 continue; 6906 } 6907 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6908 } 6909 } 6910 } 6911 } 6912 PetscFunctionReturn(PETSC_SUCCESS); 6913 } 6914 6915 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[]) 6916 { 6917 PetscInt cdof; /* The number of constraints on this point */ 6918 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6919 PetscScalar *a; 6920 PetscInt off, cind = 0, k; 6921 6922 PetscFunctionBegin; 6923 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6924 PetscCall(PetscSectionGetOffset(section, point, &off)); 6925 a = &array[off]; 6926 if (cdof) { 6927 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6928 if (clperm) { 6929 if (perm) { 6930 for (k = 0; k < dof; ++k) { 6931 if ((cind < cdof) && (k == cdofs[cind])) { 6932 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6933 cind++; 6934 } 6935 } 6936 } else { 6937 for (k = 0; k < dof; ++k) { 6938 if ((cind < cdof) && (k == cdofs[cind])) { 6939 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6940 cind++; 6941 } 6942 } 6943 } 6944 } else { 6945 if (perm) { 6946 for (k = 0; k < dof; ++k) { 6947 if ((cind < cdof) && (k == cdofs[cind])) { 6948 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6949 cind++; 6950 } 6951 } 6952 } else { 6953 for (k = 0; k < dof; ++k) { 6954 if ((cind < cdof) && (k == cdofs[cind])) { 6955 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6956 cind++; 6957 } 6958 } 6959 } 6960 } 6961 } 6962 PetscFunctionReturn(PETSC_SUCCESS); 6963 } 6964 6965 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[]) 6966 { 6967 PetscScalar *a; 6968 PetscInt fdof, foff, fcdof, foffset = *offset; 6969 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6970 PetscInt cind = 0, b; 6971 6972 PetscFunctionBegin; 6973 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6974 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6975 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6976 a = &array[foff]; 6977 if (!fcdof || setBC) { 6978 if (clperm) { 6979 if (perm) { 6980 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6981 } else { 6982 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6983 } 6984 } else { 6985 if (perm) { 6986 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6987 } else { 6988 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6989 } 6990 } 6991 } else { 6992 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6993 if (clperm) { 6994 if (perm) { 6995 for (b = 0; b < fdof; b++) { 6996 if ((cind < fcdof) && (b == fcdofs[cind])) { 6997 ++cind; 6998 continue; 6999 } 7000 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7001 } 7002 } else { 7003 for (b = 0; b < fdof; b++) { 7004 if ((cind < fcdof) && (b == fcdofs[cind])) { 7005 ++cind; 7006 continue; 7007 } 7008 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7009 } 7010 } 7011 } else { 7012 if (perm) { 7013 for (b = 0; b < fdof; b++) { 7014 if ((cind < fcdof) && (b == fcdofs[cind])) { 7015 ++cind; 7016 continue; 7017 } 7018 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7019 } 7020 } else { 7021 for (b = 0; b < fdof; b++) { 7022 if ((cind < fcdof) && (b == fcdofs[cind])) { 7023 ++cind; 7024 continue; 7025 } 7026 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7027 } 7028 } 7029 } 7030 } 7031 *offset += fdof; 7032 PetscFunctionReturn(PETSC_SUCCESS); 7033 } 7034 7035 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[]) 7036 { 7037 PetscScalar *a; 7038 PetscInt fdof, foff, fcdof, foffset = *offset; 7039 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7040 PetscInt Nc, cind = 0, ncind = 0, b; 7041 PetscBool ncSet, fcSet; 7042 7043 PetscFunctionBegin; 7044 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 7045 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7046 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 7047 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 7048 a = &array[foff]; 7049 if (fcdof) { 7050 /* We just override fcdof and fcdofs with Ncc and comps */ 7051 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7052 if (clperm) { 7053 if (perm) { 7054 if (comps) { 7055 for (b = 0; b < fdof; b++) { 7056 ncSet = fcSet = PETSC_FALSE; 7057 if (b % Nc == comps[ncind]) { 7058 ncind = (ncind + 1) % Ncc; 7059 ncSet = PETSC_TRUE; 7060 } 7061 if ((cind < fcdof) && (b == fcdofs[cind])) { 7062 ++cind; 7063 fcSet = PETSC_TRUE; 7064 } 7065 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7066 } 7067 } else { 7068 for (b = 0; b < fdof; b++) { 7069 if ((cind < fcdof) && (b == fcdofs[cind])) { 7070 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7071 ++cind; 7072 } 7073 } 7074 } 7075 } else { 7076 if (comps) { 7077 for (b = 0; b < fdof; b++) { 7078 ncSet = fcSet = PETSC_FALSE; 7079 if (b % Nc == comps[ncind]) { 7080 ncind = (ncind + 1) % Ncc; 7081 ncSet = PETSC_TRUE; 7082 } 7083 if ((cind < fcdof) && (b == fcdofs[cind])) { 7084 ++cind; 7085 fcSet = PETSC_TRUE; 7086 } 7087 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7088 } 7089 } else { 7090 for (b = 0; b < fdof; b++) { 7091 if ((cind < fcdof) && (b == fcdofs[cind])) { 7092 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7093 ++cind; 7094 } 7095 } 7096 } 7097 } 7098 } else { 7099 if (perm) { 7100 if (comps) { 7101 for (b = 0; b < fdof; b++) { 7102 ncSet = fcSet = PETSC_FALSE; 7103 if (b % Nc == comps[ncind]) { 7104 ncind = (ncind + 1) % Ncc; 7105 ncSet = PETSC_TRUE; 7106 } 7107 if ((cind < fcdof) && (b == fcdofs[cind])) { 7108 ++cind; 7109 fcSet = PETSC_TRUE; 7110 } 7111 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7112 } 7113 } else { 7114 for (b = 0; b < fdof; b++) { 7115 if ((cind < fcdof) && (b == fcdofs[cind])) { 7116 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7117 ++cind; 7118 } 7119 } 7120 } 7121 } else { 7122 if (comps) { 7123 for (b = 0; b < fdof; b++) { 7124 ncSet = fcSet = PETSC_FALSE; 7125 if (b % Nc == comps[ncind]) { 7126 ncind = (ncind + 1) % Ncc; 7127 ncSet = PETSC_TRUE; 7128 } 7129 if ((cind < fcdof) && (b == fcdofs[cind])) { 7130 ++cind; 7131 fcSet = PETSC_TRUE; 7132 } 7133 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7134 } 7135 } else { 7136 for (b = 0; b < fdof; b++) { 7137 if ((cind < fcdof) && (b == fcdofs[cind])) { 7138 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7139 ++cind; 7140 } 7141 } 7142 } 7143 } 7144 } 7145 } 7146 *offset += fdof; 7147 PetscFunctionReturn(PETSC_SUCCESS); 7148 } 7149 7150 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7151 { 7152 PetscScalar *array; 7153 const PetscInt *cone, *coneO; 7154 PetscInt pStart, pEnd, p, numPoints, off, dof; 7155 7156 PetscFunctionBeginHot; 7157 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7158 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7159 PetscCall(DMPlexGetCone(dm, point, &cone)); 7160 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7161 PetscCall(VecGetArray(v, &array)); 7162 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7163 const PetscInt cp = !p ? point : cone[p - 1]; 7164 const PetscInt o = !p ? 0 : coneO[p - 1]; 7165 7166 if ((cp < pStart) || (cp >= pEnd)) { 7167 dof = 0; 7168 continue; 7169 } 7170 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7171 /* ADD_VALUES */ 7172 { 7173 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7174 PetscScalar *a; 7175 PetscInt cdof, coff, cind = 0, k; 7176 7177 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7178 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7179 a = &array[coff]; 7180 if (!cdof) { 7181 if (o >= 0) { 7182 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7183 } else { 7184 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7185 } 7186 } else { 7187 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7188 if (o >= 0) { 7189 for (k = 0; k < dof; ++k) { 7190 if ((cind < cdof) && (k == cdofs[cind])) { 7191 ++cind; 7192 continue; 7193 } 7194 a[k] += values[off + k]; 7195 } 7196 } else { 7197 for (k = 0; k < dof; ++k) { 7198 if ((cind < cdof) && (k == cdofs[cind])) { 7199 ++cind; 7200 continue; 7201 } 7202 a[k] += values[off + dof - k - 1]; 7203 } 7204 } 7205 } 7206 } 7207 } 7208 PetscCall(VecRestoreArray(v, &array)); 7209 PetscFunctionReturn(PETSC_SUCCESS); 7210 } 7211 7212 /*@C 7213 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7214 7215 Not collective 7216 7217 Input Parameters: 7218 + dm - The `DM` 7219 . section - The section describing the layout in `v`, or `NULL` to use the default section 7220 . v - The local vector 7221 . point - The point in the `DM` 7222 . values - The array of values 7223 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7224 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7225 7226 Level: intermediate 7227 7228 Note: 7229 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7230 7231 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7232 @*/ 7233 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7234 { 7235 PetscSection clSection; 7236 IS clPoints; 7237 PetscScalar *array; 7238 PetscInt *points = NULL; 7239 const PetscInt *clp, *clperm = NULL; 7240 PetscInt depth, numFields, numPoints, p, clsize; 7241 7242 PetscFunctionBeginHot; 7243 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7244 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7245 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7246 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7247 PetscCall(DMPlexGetDepth(dm, &depth)); 7248 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7249 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7250 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7251 PetscFunctionReturn(PETSC_SUCCESS); 7252 } 7253 /* Get points */ 7254 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7255 for (clsize = 0, p = 0; p < numPoints; p++) { 7256 PetscInt dof; 7257 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7258 clsize += dof; 7259 } 7260 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7261 /* Get array */ 7262 PetscCall(VecGetArray(v, &array)); 7263 /* Get values */ 7264 if (numFields > 0) { 7265 PetscInt offset = 0, f; 7266 for (f = 0; f < numFields; ++f) { 7267 const PetscInt **perms = NULL; 7268 const PetscScalar **flips = NULL; 7269 7270 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7271 switch (mode) { 7272 case INSERT_VALUES: 7273 for (p = 0; p < numPoints; p++) { 7274 const PetscInt point = points[2 * p]; 7275 const PetscInt *perm = perms ? perms[p] : NULL; 7276 const PetscScalar *flip = flips ? flips[p] : NULL; 7277 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7278 } 7279 break; 7280 case INSERT_ALL_VALUES: 7281 for (p = 0; p < numPoints; p++) { 7282 const PetscInt point = points[2 * p]; 7283 const PetscInt *perm = perms ? perms[p] : NULL; 7284 const PetscScalar *flip = flips ? flips[p] : NULL; 7285 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7286 } 7287 break; 7288 case INSERT_BC_VALUES: 7289 for (p = 0; p < numPoints; p++) { 7290 const PetscInt point = points[2 * p]; 7291 const PetscInt *perm = perms ? perms[p] : NULL; 7292 const PetscScalar *flip = flips ? flips[p] : NULL; 7293 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7294 } 7295 break; 7296 case ADD_VALUES: 7297 for (p = 0; p < numPoints; p++) { 7298 const PetscInt point = points[2 * p]; 7299 const PetscInt *perm = perms ? perms[p] : NULL; 7300 const PetscScalar *flip = flips ? flips[p] : NULL; 7301 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7302 } 7303 break; 7304 case ADD_ALL_VALUES: 7305 for (p = 0; p < numPoints; p++) { 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(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7310 } 7311 break; 7312 case ADD_BC_VALUES: 7313 for (p = 0; p < numPoints; p++) { 7314 const PetscInt point = points[2 * p]; 7315 const PetscInt *perm = perms ? perms[p] : NULL; 7316 const PetscScalar *flip = flips ? flips[p] : NULL; 7317 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7318 } 7319 break; 7320 default: 7321 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7322 } 7323 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7324 } 7325 } else { 7326 PetscInt dof, off; 7327 const PetscInt **perms = NULL; 7328 const PetscScalar **flips = NULL; 7329 7330 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7331 switch (mode) { 7332 case INSERT_VALUES: 7333 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7334 const PetscInt point = points[2 * p]; 7335 const PetscInt *perm = perms ? perms[p] : NULL; 7336 const PetscScalar *flip = flips ? flips[p] : NULL; 7337 PetscCall(PetscSectionGetDof(section, point, &dof)); 7338 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7339 } 7340 break; 7341 case INSERT_ALL_VALUES: 7342 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7343 const PetscInt point = points[2 * p]; 7344 const PetscInt *perm = perms ? perms[p] : NULL; 7345 const PetscScalar *flip = flips ? flips[p] : NULL; 7346 PetscCall(PetscSectionGetDof(section, point, &dof)); 7347 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7348 } 7349 break; 7350 case INSERT_BC_VALUES: 7351 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7352 const PetscInt point = points[2 * p]; 7353 const PetscInt *perm = perms ? perms[p] : NULL; 7354 const PetscScalar *flip = flips ? flips[p] : NULL; 7355 PetscCall(PetscSectionGetDof(section, point, &dof)); 7356 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7357 } 7358 break; 7359 case ADD_VALUES: 7360 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7361 const PetscInt point = points[2 * p]; 7362 const PetscInt *perm = perms ? perms[p] : NULL; 7363 const PetscScalar *flip = flips ? flips[p] : NULL; 7364 PetscCall(PetscSectionGetDof(section, point, &dof)); 7365 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7366 } 7367 break; 7368 case ADD_ALL_VALUES: 7369 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7370 const PetscInt point = points[2 * p]; 7371 const PetscInt *perm = perms ? perms[p] : NULL; 7372 const PetscScalar *flip = flips ? flips[p] : NULL; 7373 PetscCall(PetscSectionGetDof(section, point, &dof)); 7374 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7375 } 7376 break; 7377 case ADD_BC_VALUES: 7378 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7379 const PetscInt point = points[2 * p]; 7380 const PetscInt *perm = perms ? perms[p] : NULL; 7381 const PetscScalar *flip = flips ? flips[p] : NULL; 7382 PetscCall(PetscSectionGetDof(section, point, &dof)); 7383 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7384 } 7385 break; 7386 default: 7387 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7388 } 7389 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7390 } 7391 /* Cleanup points */ 7392 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7393 /* Cleanup array */ 7394 PetscCall(VecRestoreArray(v, &array)); 7395 PetscFunctionReturn(PETSC_SUCCESS); 7396 } 7397 7398 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7399 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7400 { 7401 PetscFunctionBegin; 7402 *contains = PETSC_TRUE; 7403 if (label) { 7404 PetscInt fdof; 7405 7406 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7407 if (!*contains) { 7408 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7409 *offset += fdof; 7410 PetscFunctionReturn(PETSC_SUCCESS); 7411 } 7412 } 7413 PetscFunctionReturn(PETSC_SUCCESS); 7414 } 7415 7416 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7417 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) 7418 { 7419 PetscSection clSection; 7420 IS clPoints; 7421 PetscScalar *array; 7422 PetscInt *points = NULL; 7423 const PetscInt *clp; 7424 PetscInt numFields, numPoints, p; 7425 PetscInt offset = 0, f; 7426 7427 PetscFunctionBeginHot; 7428 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7429 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7430 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7431 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7432 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7433 /* Get points */ 7434 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7435 /* Get array */ 7436 PetscCall(VecGetArray(v, &array)); 7437 /* Get values */ 7438 for (f = 0; f < numFields; ++f) { 7439 const PetscInt **perms = NULL; 7440 const PetscScalar **flips = NULL; 7441 PetscBool contains; 7442 7443 if (!fieldActive[f]) { 7444 for (p = 0; p < numPoints * 2; p += 2) { 7445 PetscInt fdof; 7446 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7447 offset += fdof; 7448 } 7449 continue; 7450 } 7451 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7452 switch (mode) { 7453 case INSERT_VALUES: 7454 for (p = 0; p < numPoints; p++) { 7455 const PetscInt point = points[2 * p]; 7456 const PetscInt *perm = perms ? perms[p] : NULL; 7457 const PetscScalar *flip = flips ? flips[p] : NULL; 7458 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7459 if (!contains) continue; 7460 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7461 } 7462 break; 7463 case INSERT_ALL_VALUES: 7464 for (p = 0; p < numPoints; p++) { 7465 const PetscInt point = points[2 * p]; 7466 const PetscInt *perm = perms ? perms[p] : NULL; 7467 const PetscScalar *flip = flips ? flips[p] : NULL; 7468 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7469 if (!contains) continue; 7470 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7471 } 7472 break; 7473 case INSERT_BC_VALUES: 7474 for (p = 0; p < numPoints; p++) { 7475 const PetscInt point = points[2 * p]; 7476 const PetscInt *perm = perms ? perms[p] : NULL; 7477 const PetscScalar *flip = flips ? flips[p] : NULL; 7478 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7479 if (!contains) continue; 7480 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7481 } 7482 break; 7483 case ADD_VALUES: 7484 for (p = 0; p < numPoints; p++) { 7485 const PetscInt point = points[2 * p]; 7486 const PetscInt *perm = perms ? perms[p] : NULL; 7487 const PetscScalar *flip = flips ? flips[p] : NULL; 7488 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7489 if (!contains) continue; 7490 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7491 } 7492 break; 7493 case ADD_ALL_VALUES: 7494 for (p = 0; p < numPoints; p++) { 7495 const PetscInt point = points[2 * p]; 7496 const PetscInt *perm = perms ? perms[p] : NULL; 7497 const PetscScalar *flip = flips ? flips[p] : NULL; 7498 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7499 if (!contains) continue; 7500 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7501 } 7502 break; 7503 default: 7504 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7505 } 7506 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7507 } 7508 /* Cleanup points */ 7509 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7510 /* Cleanup array */ 7511 PetscCall(VecRestoreArray(v, &array)); 7512 PetscFunctionReturn(PETSC_SUCCESS); 7513 } 7514 7515 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7516 { 7517 PetscMPIInt rank; 7518 PetscInt i, j; 7519 7520 PetscFunctionBegin; 7521 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7522 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7523 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7524 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7525 numCIndices = numCIndices ? numCIndices : numRIndices; 7526 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7527 for (i = 0; i < numRIndices; i++) { 7528 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7529 for (j = 0; j < numCIndices; j++) { 7530 #if defined(PETSC_USE_COMPLEX) 7531 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7532 #else 7533 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7534 #endif 7535 } 7536 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7537 } 7538 PetscFunctionReturn(PETSC_SUCCESS); 7539 } 7540 7541 /* 7542 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7543 7544 Input Parameters: 7545 + section - The section for this data layout 7546 . islocal - Is the section (and thus indices being requested) local or global? 7547 . point - The point contributing dofs with these indices 7548 . off - The global offset of this point 7549 . loff - The local offset of each field 7550 . setBC - The flag determining whether to include indices of boundary values 7551 . perm - A permutation of the dofs on this point, or NULL 7552 - indperm - A permutation of the entire indices array, or NULL 7553 7554 Output Parameter: 7555 . indices - Indices for dofs on this point 7556 7557 Level: developer 7558 7559 Note: The indices could be local or global, depending on the value of 'off'. 7560 */ 7561 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7562 { 7563 PetscInt dof; /* The number of unknowns on this point */ 7564 PetscInt cdof; /* The number of constraints on this point */ 7565 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7566 PetscInt cind = 0, k; 7567 7568 PetscFunctionBegin; 7569 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7570 PetscCall(PetscSectionGetDof(section, point, &dof)); 7571 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7572 if (!cdof || setBC) { 7573 for (k = 0; k < dof; ++k) { 7574 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7575 const PetscInt ind = indperm ? indperm[preind] : preind; 7576 7577 indices[ind] = off + k; 7578 } 7579 } else { 7580 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7581 for (k = 0; k < dof; ++k) { 7582 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7583 const PetscInt ind = indperm ? indperm[preind] : preind; 7584 7585 if ((cind < cdof) && (k == cdofs[cind])) { 7586 /* Insert check for returning constrained indices */ 7587 indices[ind] = -(off + k + 1); 7588 ++cind; 7589 } else { 7590 indices[ind] = off + k - (islocal ? 0 : cind); 7591 } 7592 } 7593 } 7594 *loff += dof; 7595 PetscFunctionReturn(PETSC_SUCCESS); 7596 } 7597 7598 /* 7599 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7600 7601 Input Parameters: 7602 + section - a section (global or local) 7603 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7604 . point - point within section 7605 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7606 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7607 . setBC - identify constrained (boundary condition) points via involution. 7608 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7609 . permsoff - offset 7610 - indperm - index permutation 7611 7612 Output Parameter: 7613 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7614 . indices - array to hold indices (as defined by section) of each dof associated with point 7615 7616 Notes: 7617 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7618 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7619 in the local vector. 7620 7621 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7622 significant). It is invalid to call with a global section and setBC=true. 7623 7624 Developer Note: 7625 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7626 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7627 offset could be obtained from the section instead of passing it explicitly as we do now. 7628 7629 Example: 7630 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7631 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7632 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7633 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. 7634 7635 Level: developer 7636 */ 7637 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[]) 7638 { 7639 PetscInt numFields, foff, f; 7640 7641 PetscFunctionBegin; 7642 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7643 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7644 for (f = 0, foff = 0; f < numFields; ++f) { 7645 PetscInt fdof, cfdof; 7646 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7647 PetscInt cind = 0, b; 7648 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7649 7650 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7651 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7652 if (!cfdof || setBC) { 7653 for (b = 0; b < fdof; ++b) { 7654 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7655 const PetscInt ind = indperm ? indperm[preind] : preind; 7656 7657 indices[ind] = off + foff + b; 7658 } 7659 } else { 7660 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7661 for (b = 0; b < fdof; ++b) { 7662 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7663 const PetscInt ind = indperm ? indperm[preind] : preind; 7664 7665 if ((cind < cfdof) && (b == fcdofs[cind])) { 7666 indices[ind] = -(off + foff + b + 1); 7667 ++cind; 7668 } else { 7669 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7670 } 7671 } 7672 } 7673 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7674 foffs[f] += fdof; 7675 } 7676 PetscFunctionReturn(PETSC_SUCCESS); 7677 } 7678 7679 /* 7680 This version believes the globalSection offsets for each field, rather than just the point offset 7681 7682 . foffs - The offset into 'indices' for each field, since it is segregated by field 7683 7684 Notes: 7685 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7686 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7687 */ 7688 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7689 { 7690 PetscInt numFields, foff, f; 7691 7692 PetscFunctionBegin; 7693 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7694 for (f = 0; f < numFields; ++f) { 7695 PetscInt fdof, cfdof; 7696 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7697 PetscInt cind = 0, b; 7698 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7699 7700 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7701 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7702 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7703 if (!cfdof) { 7704 for (b = 0; b < fdof; ++b) { 7705 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7706 const PetscInt ind = indperm ? indperm[preind] : preind; 7707 7708 indices[ind] = foff + b; 7709 } 7710 } else { 7711 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7712 for (b = 0; b < fdof; ++b) { 7713 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7714 const PetscInt ind = indperm ? indperm[preind] : preind; 7715 7716 if ((cind < cfdof) && (b == fcdofs[cind])) { 7717 indices[ind] = -(foff + b + 1); 7718 ++cind; 7719 } else { 7720 indices[ind] = foff + b - cind; 7721 } 7722 } 7723 } 7724 foffs[f] += fdof; 7725 } 7726 PetscFunctionReturn(PETSC_SUCCESS); 7727 } 7728 7729 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7730 { 7731 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7732 7733 PetscFunctionBegin; 7734 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7735 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7736 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7737 for (PetscInt p = 0; p < nPoints; p++) { 7738 PetscInt b = pnts[2 * p]; 7739 PetscInt bSecDof = 0, bOff; 7740 PetscInt cSecDof = 0; 7741 PetscSection indices_section; 7742 7743 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7744 if (!bSecDof) continue; 7745 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7746 indices_section = cSecDof > 0 ? cSec : section; 7747 if (numFields) { 7748 PetscInt fStart[32], fEnd[32]; 7749 7750 fStart[0] = 0; 7751 fEnd[0] = 0; 7752 for (PetscInt f = 0; f < numFields; f++) { 7753 PetscInt fDof = 0; 7754 7755 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7756 fStart[f + 1] = fStart[f] + fDof; 7757 fEnd[f + 1] = fStart[f + 1]; 7758 } 7759 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7760 // only apply permutations on one side 7761 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7762 for (PetscInt f = 0; f < numFields; f++) { 7763 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7764 } 7765 } else { 7766 PetscInt bEnd = 0; 7767 7768 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7769 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7770 7771 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7772 } 7773 } 7774 PetscFunctionReturn(PETSC_SUCCESS); 7775 } 7776 7777 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[]) 7778 { 7779 Mat cMat; 7780 PetscSection aSec, cSec; 7781 IS aIS; 7782 PetscInt aStart = -1, aEnd = -1; 7783 PetscInt sStart = -1, sEnd = -1; 7784 PetscInt cStart = -1, cEnd = -1; 7785 const PetscInt *anchors; 7786 PetscInt numFields, p; 7787 PetscInt newNumPoints = 0, newNumIndices = 0; 7788 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7789 PetscInt oldOffsets[32]; 7790 PetscInt newOffsets[32]; 7791 PetscInt oldOffsetsCopy[32]; 7792 PetscInt newOffsetsCopy[32]; 7793 PetscScalar *modMat = NULL; 7794 PetscBool anyConstrained = PETSC_FALSE; 7795 7796 PetscFunctionBegin; 7797 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7798 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7799 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7800 7801 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7802 /* if there are point-to-point constraints */ 7803 if (aSec) { 7804 PetscCall(PetscArrayzero(newOffsets, 32)); 7805 PetscCall(PetscArrayzero(oldOffsets, 32)); 7806 PetscCall(ISGetIndices(aIS, &anchors)); 7807 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7808 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7809 /* figure out how many points are going to be in the new element matrix 7810 * (we allow double counting, because it's all just going to be summed 7811 * into the global matrix anyway) */ 7812 for (p = 0; p < 2 * numPoints; p += 2) { 7813 PetscInt b = points[p]; 7814 PetscInt bDof = 0, bSecDof = 0; 7815 7816 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7817 if (!bSecDof) continue; 7818 7819 for (PetscInt f = 0; f < numFields; f++) { 7820 PetscInt fDof = 0; 7821 7822 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7823 oldOffsets[f + 1] += fDof; 7824 } 7825 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7826 if (bDof) { 7827 /* this point is constrained */ 7828 /* it is going to be replaced by its anchors */ 7829 PetscInt bOff, q; 7830 7831 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7832 for (q = 0; q < bDof; q++) { 7833 PetscInt a = anchors[bOff + q]; 7834 PetscInt aDof = 0; 7835 7836 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7837 if (aDof) { 7838 anyConstrained = PETSC_TRUE; 7839 newNumPoints += 1; 7840 } 7841 newNumIndices += aDof; 7842 for (PetscInt f = 0; f < numFields; ++f) { 7843 PetscInt fDof = 0; 7844 7845 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7846 newOffsets[f + 1] += fDof; 7847 } 7848 } 7849 } else { 7850 /* this point is not constrained */ 7851 newNumPoints++; 7852 newNumIndices += bSecDof; 7853 for (PetscInt f = 0; f < numFields; ++f) { 7854 PetscInt fDof; 7855 7856 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7857 newOffsets[f + 1] += fDof; 7858 } 7859 } 7860 } 7861 } 7862 if (!anyConstrained) { 7863 if (outNumPoints) *outNumPoints = 0; 7864 if (outNumIndices) *outNumIndices = 0; 7865 if (outPoints) *outPoints = NULL; 7866 if (outMat) *outMat = NULL; 7867 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7868 PetscFunctionReturn(PETSC_SUCCESS); 7869 } 7870 7871 if (outNumPoints) *outNumPoints = newNumPoints; 7872 if (outNumIndices) *outNumIndices = newNumIndices; 7873 7874 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7875 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7876 7877 if (!outPoints && !outMat) { 7878 if (offsets) { 7879 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7880 } 7881 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7882 PetscFunctionReturn(PETSC_SUCCESS); 7883 } 7884 7885 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7886 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7887 7888 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7889 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7890 7891 /* output arrays */ 7892 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7893 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7894 7895 // get the new Points 7896 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7897 PetscInt b = points[2 * p]; 7898 PetscInt bDof = 0, bSecDof = 0, bOff; 7899 7900 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7901 if (!bSecDof) continue; 7902 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7903 if (bDof) { 7904 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7905 for (PetscInt q = 0; q < bDof; q++) { 7906 PetscInt a = anchors[bOff + q], aDof = 0; 7907 7908 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7909 if (aDof) { 7910 newPoints[2 * newP] = a; 7911 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7912 newP++; 7913 } 7914 } 7915 } else { 7916 newPoints[2 * newP] = b; 7917 newPoints[2 * newP + 1] = points[2 * p + 1]; 7918 newP++; 7919 } 7920 } 7921 7922 if (outMat) { 7923 PetscScalar *tmpMat; 7924 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7925 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7926 7927 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7928 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7929 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7930 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7931 7932 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7933 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7934 7935 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7936 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7937 7938 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7939 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7940 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7941 // for each field, insert the anchor modification into modMat 7942 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7943 PetscInt fStart = oldOffsets[f]; 7944 PetscInt fNewStart = newOffsets[f]; 7945 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7946 PetscInt b = points[2 * p]; 7947 PetscInt bDof = 0, bSecDof = 0, bOff; 7948 7949 if (b >= sStart && b < sEnd) { 7950 if (numFields) { 7951 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7952 } else { 7953 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7954 } 7955 } 7956 if (!bSecDof) continue; 7957 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7958 if (bDof) { 7959 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7960 for (PetscInt q = 0; q < bDof; q++, newP++) { 7961 PetscInt a = anchors[bOff + q], aDof = 0; 7962 7963 if (a >= sStart && a < sEnd) { 7964 if (numFields) { 7965 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7966 } else { 7967 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7968 } 7969 } 7970 if (aDof) { 7971 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7972 for (PetscInt d = 0; d < bSecDof; d++) { 7973 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7974 } 7975 } 7976 oNew += aDof; 7977 } 7978 } else { 7979 // Insert the identity matrix in this block 7980 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7981 oNew += bSecDof; 7982 newP++; 7983 } 7984 o += bSecDof; 7985 } 7986 } 7987 7988 *outMat = modMat; 7989 7990 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7991 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7992 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7993 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7994 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7995 } 7996 PetscCall(ISRestoreIndices(aIS, &anchors)); 7997 7998 /* output */ 7999 if (outPoints) { 8000 *outPoints = newPoints; 8001 } else { 8002 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 8003 } 8004 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 8005 PetscFunctionReturn(PETSC_SUCCESS); 8006 } 8007 8008 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) 8009 { 8010 PetscScalar *modMat = NULL; 8011 PetscInt newNumIndices = -1; 8012 8013 PetscFunctionBegin; 8014 /* 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. 8015 modMat is that matrix C */ 8016 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 8017 if (outNumIndices) *outNumIndices = newNumIndices; 8018 if (modMat) { 8019 const PetscScalar *newValues = values; 8020 8021 if (multiplyRight) { 8022 PetscScalar *newNewValues = NULL; 8023 PetscBLASInt M, N, K; 8024 PetscScalar a = 1.0, b = 0.0; 8025 8026 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); 8027 8028 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 8029 PetscCall(PetscBLASIntCast(numRows, &N)); 8030 PetscCall(PetscBLASIntCast(numIndices, &K)); 8031 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 8032 // row-major to column-major conversion, right multiplication becomes left multiplication 8033 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 8034 numCols = newNumIndices; 8035 newValues = newNewValues; 8036 } 8037 8038 if (multiplyLeft) { 8039 PetscScalar *newNewValues = NULL; 8040 PetscBLASInt M, N, K; 8041 PetscScalar a = 1.0, b = 0.0; 8042 8043 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); 8044 8045 PetscCall(PetscBLASIntCast(numCols, &M)); 8046 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 8047 PetscCall(PetscBLASIntCast(numIndices, &K)); 8048 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 8049 // row-major to column-major conversion, left multiplication becomes right multiplication 8050 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 8051 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 8052 newValues = newNewValues; 8053 } 8054 *outValues = (PetscScalar *)newValues; 8055 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 8056 } 8057 PetscFunctionReturn(PETSC_SUCCESS); 8058 } 8059 8060 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) 8061 { 8062 PetscFunctionBegin; 8063 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 8064 PetscFunctionReturn(PETSC_SUCCESS); 8065 } 8066 8067 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 8068 { 8069 /* Closure ordering */ 8070 PetscSection clSection; 8071 IS clPoints; 8072 const PetscInt *clp; 8073 PetscInt *points; 8074 PetscInt Ncl, Ni = 0; 8075 8076 PetscFunctionBeginHot; 8077 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8078 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 8079 PetscInt dof; 8080 8081 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8082 Ni += dof; 8083 } 8084 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8085 *closureSize = Ni; 8086 PetscFunctionReturn(PETSC_SUCCESS); 8087 } 8088 8089 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) 8090 { 8091 /* Closure ordering */ 8092 PetscSection clSection; 8093 IS clPoints; 8094 const PetscInt *clp; 8095 PetscInt *points; 8096 const PetscInt *clperm = NULL; 8097 /* Dof permutation and sign flips */ 8098 const PetscInt **perms[32] = {NULL}; 8099 const PetscScalar **flips[32] = {NULL}; 8100 PetscScalar *valCopy = NULL; 8101 /* Hanging node constraints */ 8102 PetscInt *pointsC = NULL; 8103 PetscScalar *valuesC = NULL; 8104 PetscInt NclC, NiC; 8105 8106 PetscInt *idx; 8107 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8108 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8109 PetscInt idxStart, idxEnd; 8110 PetscInt nRows, nCols; 8111 8112 PetscFunctionBeginHot; 8113 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8114 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8115 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8116 PetscAssertPointer(numRows, 6); 8117 PetscAssertPointer(numCols, 7); 8118 if (indices) PetscAssertPointer(indices, 8); 8119 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8120 if (values) PetscAssertPointer(values, 10); 8121 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8122 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8123 PetscCall(PetscArrayzero(offsets, 32)); 8124 /* 1) Get points in closure */ 8125 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8126 if (useClPerm) { 8127 PetscInt depth, clsize; 8128 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8129 for (clsize = 0, p = 0; p < Ncl; p++) { 8130 PetscInt dof; 8131 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8132 clsize += dof; 8133 } 8134 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8135 } 8136 /* 2) Get number of indices on these points and field offsets from section */ 8137 for (p = 0; p < Ncl * 2; p += 2) { 8138 PetscInt dof, fdof; 8139 8140 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8141 for (f = 0; f < Nf; ++f) { 8142 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8143 offsets[f + 1] += fdof; 8144 } 8145 Ni += dof; 8146 } 8147 if (*numRows == -1) *numRows = Ni; 8148 if (*numCols == -1) *numCols = Ni; 8149 nRows = *numRows; 8150 nCols = *numCols; 8151 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8152 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8153 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8154 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8155 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8156 for (f = 0; f < PetscMax(1, Nf); ++f) { 8157 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8158 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8159 /* may need to apply sign changes to the element matrix */ 8160 if (values && flips[f]) { 8161 PetscInt foffset = offsets[f]; 8162 8163 for (p = 0; p < Ncl; ++p) { 8164 PetscInt pnt = points[2 * p], fdof; 8165 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8166 8167 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8168 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8169 if (flip) { 8170 PetscInt i, j, k; 8171 8172 if (!valCopy) { 8173 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8174 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8175 *values = valCopy; 8176 } 8177 for (i = 0; i < fdof; ++i) { 8178 PetscScalar fval = flip[i]; 8179 8180 if (multiplyRight) { 8181 for (k = 0; k < nRows; ++k) valCopy[Ni * k + (foffset + i)] *= fval; 8182 } 8183 if (multiplyLeft) { 8184 for (k = 0; k < nCols; ++k) valCopy[nCols * (foffset + i) + k] *= fval; 8185 } 8186 } 8187 } 8188 foffset += fdof; 8189 } 8190 } 8191 } 8192 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8193 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8194 if (NclC) { 8195 if (multiplyRight) *numCols = NiC; 8196 if (multiplyLeft) *numRows = NiC; 8197 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8198 for (f = 0; f < PetscMax(1, Nf); ++f) { 8199 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8200 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8201 } 8202 for (f = 0; f < PetscMax(1, Nf); ++f) { 8203 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8204 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8205 } 8206 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8207 Ncl = NclC; 8208 Ni = NiC; 8209 points = pointsC; 8210 if (values) *values = valuesC; 8211 } 8212 /* 5) Calculate indices */ 8213 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8214 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8215 if (Nf) { 8216 PetscInt idxOff; 8217 PetscBool useFieldOffsets; 8218 8219 if (outOffsets) { 8220 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8221 } 8222 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8223 if (useFieldOffsets) { 8224 for (p = 0; p < Ncl; ++p) { 8225 const PetscInt pnt = points[p * 2]; 8226 8227 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8228 } 8229 } else { 8230 for (p = 0; p < Ncl; ++p) { 8231 const PetscInt pnt = points[p * 2]; 8232 8233 if (pnt < idxStart || pnt >= idxEnd) continue; 8234 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8235 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8236 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8237 * global section. */ 8238 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8239 } 8240 } 8241 } else { 8242 PetscInt off = 0, idxOff; 8243 8244 for (p = 0; p < Ncl; ++p) { 8245 const PetscInt pnt = points[p * 2]; 8246 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8247 8248 if (pnt < idxStart || pnt >= idxEnd) continue; 8249 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8250 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8251 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8252 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8253 } 8254 } 8255 /* 6) Cleanup */ 8256 for (f = 0; f < PetscMax(1, Nf); ++f) { 8257 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8258 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8259 } 8260 if (NclC) { 8261 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8262 } else { 8263 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8264 } 8265 8266 if (indices) *indices = idx; 8267 PetscFunctionReturn(PETSC_SUCCESS); 8268 } 8269 8270 /*@C 8271 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8272 8273 Not collective 8274 8275 Input Parameters: 8276 + dm - The `DM` 8277 . section - The `PetscSection` describing the points (a local section) 8278 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8279 . point - The point defining the closure 8280 - useClPerm - Use the closure point permutation if available 8281 8282 Output Parameters: 8283 + numIndices - The number of dof indices in the closure of point with the input sections 8284 . indices - The dof indices 8285 . outOffsets - Array to write the field offsets into, or `NULL` 8286 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8287 8288 Level: advanced 8289 8290 Notes: 8291 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8292 8293 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8294 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8295 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8296 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8297 indices (with the above semantics) are implied. 8298 8299 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8300 `PetscSection`, `DMGetGlobalSection()` 8301 @*/ 8302 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8303 { 8304 PetscInt numRows = -1, numCols = -1; 8305 8306 PetscFunctionBeginHot; 8307 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8308 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8309 *numIndices = numRows; 8310 PetscFunctionReturn(PETSC_SUCCESS); 8311 } 8312 8313 /*@C 8314 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8315 8316 Not collective 8317 8318 Input Parameters: 8319 + dm - The `DM` 8320 . section - The `PetscSection` describing the points (a local section) 8321 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8322 . point - The point defining the closure 8323 - useClPerm - Use the closure point permutation if available 8324 8325 Output Parameters: 8326 + numIndices - The number of dof indices in the closure of point with the input sections 8327 . indices - The dof indices 8328 . outOffsets - Array to write the field offsets into, or `NULL` 8329 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8330 8331 Level: advanced 8332 8333 Notes: 8334 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8335 8336 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8337 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8338 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8339 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8340 indices (with the above semantics) are implied. 8341 8342 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8343 @*/ 8344 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8345 { 8346 PetscFunctionBegin; 8347 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8348 PetscAssertPointer(indices, 7); 8349 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8350 PetscFunctionReturn(PETSC_SUCCESS); 8351 } 8352 8353 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8354 { 8355 DM_Plex *mesh = (DM_Plex *)dm->data; 8356 PetscInt *indices; 8357 PetscInt numIndices; 8358 const PetscScalar *valuesOrig = values; 8359 PetscErrorCode ierr; 8360 8361 PetscFunctionBegin; 8362 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8363 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8364 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8365 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8366 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8367 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8368 8369 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8370 8371 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8372 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8373 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8374 if (ierr) { 8375 PetscMPIInt rank; 8376 8377 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8378 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8379 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8380 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8381 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8382 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8383 } 8384 if (mesh->printFEM > 1) { 8385 PetscInt i; 8386 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8387 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8388 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8389 } 8390 8391 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8392 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8393 PetscFunctionReturn(PETSC_SUCCESS); 8394 } 8395 8396 /*@C 8397 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8398 8399 Not collective 8400 8401 Input Parameters: 8402 + dm - The `DM` 8403 . section - The section describing the layout in `v`, or `NULL` to use the default section 8404 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8405 . A - The matrix 8406 . point - The point in the `DM` 8407 . values - The array of values 8408 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8409 8410 Level: intermediate 8411 8412 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8413 @*/ 8414 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8415 { 8416 PetscFunctionBegin; 8417 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8418 PetscFunctionReturn(PETSC_SUCCESS); 8419 } 8420 8421 /*@C 8422 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8423 8424 Not collective 8425 8426 Input Parameters: 8427 + dmRow - The `DM` for the row fields 8428 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8429 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8430 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8431 . dmCol - The `DM` for the column fields 8432 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8433 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8434 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8435 . A - The matrix 8436 . point - The point in the `DM` 8437 . values - The array of values 8438 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8439 8440 Level: intermediate 8441 8442 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8443 @*/ 8444 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) 8445 { 8446 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8447 PetscInt *indicesRow, *indicesCol; 8448 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8449 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8450 8451 PetscErrorCode ierr; 8452 8453 PetscFunctionBegin; 8454 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8455 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8456 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8457 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8458 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8459 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8460 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8461 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8462 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8463 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8464 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8465 8466 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8467 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8468 valuesV1 = valuesV0; 8469 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8470 valuesV2 = valuesV1; 8471 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8472 8473 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8474 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8475 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8476 if (ierr) { 8477 PetscMPIInt rank; 8478 8479 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8480 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8481 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8482 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8483 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8484 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8485 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8486 } 8487 8488 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8489 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8490 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8491 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8492 PetscFunctionReturn(PETSC_SUCCESS); 8493 } 8494 8495 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8496 { 8497 DM_Plex *mesh = (DM_Plex *)dmf->data; 8498 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8499 PetscInt *cpoints = NULL; 8500 PetscInt *findices, *cindices; 8501 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8502 PetscInt foffsets[32], coffsets[32]; 8503 DMPolytopeType ct; 8504 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8505 PetscErrorCode ierr; 8506 8507 PetscFunctionBegin; 8508 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8509 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8510 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8511 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8512 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8513 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8514 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8515 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8516 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8517 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8518 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8519 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8520 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8521 PetscCall(PetscArrayzero(foffsets, 32)); 8522 PetscCall(PetscArrayzero(coffsets, 32)); 8523 /* Column indices */ 8524 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8525 maxFPoints = numCPoints; 8526 /* Compress out points not in the section */ 8527 /* TODO: Squeeze out points with 0 dof as well */ 8528 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8529 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8530 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8531 cpoints[q * 2] = cpoints[p]; 8532 cpoints[q * 2 + 1] = cpoints[p + 1]; 8533 ++q; 8534 } 8535 } 8536 numCPoints = q; 8537 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8538 PetscInt fdof; 8539 8540 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8541 if (!dof) continue; 8542 for (f = 0; f < numFields; ++f) { 8543 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8544 coffsets[f + 1] += fdof; 8545 } 8546 numCIndices += dof; 8547 } 8548 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8549 /* Row indices */ 8550 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8551 { 8552 DMPlexTransform tr; 8553 DMPolytopeType *rct; 8554 PetscInt *rsize, *rcone, *rornt, Nt; 8555 8556 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8557 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8558 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8559 numSubcells = rsize[Nt - 1]; 8560 PetscCall(DMPlexTransformDestroy(&tr)); 8561 } 8562 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8563 for (r = 0, q = 0; r < numSubcells; ++r) { 8564 /* TODO Map from coarse to fine cells */ 8565 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8566 /* Compress out points not in the section */ 8567 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8568 for (p = 0; p < numFPoints * 2; p += 2) { 8569 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8570 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8571 if (!dof) continue; 8572 for (s = 0; s < q; ++s) 8573 if (fpoints[p] == ftotpoints[s * 2]) break; 8574 if (s < q) continue; 8575 ftotpoints[q * 2] = fpoints[p]; 8576 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8577 ++q; 8578 } 8579 } 8580 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8581 } 8582 numFPoints = q; 8583 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8584 PetscInt fdof; 8585 8586 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8587 if (!dof) continue; 8588 for (f = 0; f < numFields; ++f) { 8589 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8590 foffsets[f + 1] += fdof; 8591 } 8592 numFIndices += dof; 8593 } 8594 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8595 8596 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8597 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8598 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8599 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8600 if (numFields) { 8601 const PetscInt **permsF[32] = {NULL}; 8602 const PetscInt **permsC[32] = {NULL}; 8603 8604 for (f = 0; f < numFields; f++) { 8605 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8606 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8607 } 8608 for (p = 0; p < numFPoints; p++) { 8609 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8610 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8611 } 8612 for (p = 0; p < numCPoints; p++) { 8613 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8614 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8615 } 8616 for (f = 0; f < numFields; f++) { 8617 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8618 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8619 } 8620 } else { 8621 const PetscInt **permsF = NULL; 8622 const PetscInt **permsC = NULL; 8623 8624 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8625 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8626 for (p = 0, off = 0; p < numFPoints; p++) { 8627 const PetscInt *perm = permsF ? permsF[p] : NULL; 8628 8629 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8630 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8631 } 8632 for (p = 0, off = 0; p < numCPoints; p++) { 8633 const PetscInt *perm = permsC ? permsC[p] : NULL; 8634 8635 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8636 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8637 } 8638 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8639 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8640 } 8641 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8642 /* TODO: flips */ 8643 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8644 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8645 if (ierr) { 8646 PetscMPIInt rank; 8647 8648 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8649 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8650 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8651 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8652 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8653 } 8654 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8655 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8656 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8657 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8658 PetscFunctionReturn(PETSC_SUCCESS); 8659 } 8660 8661 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8662 { 8663 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8664 PetscInt *cpoints = NULL; 8665 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8666 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8667 DMPolytopeType ct; 8668 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8669 8670 PetscFunctionBegin; 8671 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8672 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8673 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8674 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8675 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8676 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8677 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8678 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8679 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8680 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8681 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8682 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8683 /* Column indices */ 8684 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8685 maxFPoints = numCPoints; 8686 /* Compress out points not in the section */ 8687 /* TODO: Squeeze out points with 0 dof as well */ 8688 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8689 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8690 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8691 cpoints[q * 2] = cpoints[p]; 8692 cpoints[q * 2 + 1] = cpoints[p + 1]; 8693 ++q; 8694 } 8695 } 8696 numCPoints = q; 8697 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8698 PetscInt fdof; 8699 8700 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8701 if (!dof) continue; 8702 for (f = 0; f < numFields; ++f) { 8703 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8704 coffsets[f + 1] += fdof; 8705 } 8706 numCIndices += dof; 8707 } 8708 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8709 /* Row indices */ 8710 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8711 { 8712 DMPlexTransform tr; 8713 DMPolytopeType *rct; 8714 PetscInt *rsize, *rcone, *rornt, Nt; 8715 8716 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8717 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8718 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8719 numSubcells = rsize[Nt - 1]; 8720 PetscCall(DMPlexTransformDestroy(&tr)); 8721 } 8722 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8723 for (r = 0, q = 0; r < numSubcells; ++r) { 8724 /* TODO Map from coarse to fine cells */ 8725 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8726 /* Compress out points not in the section */ 8727 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8728 for (p = 0; p < numFPoints * 2; p += 2) { 8729 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8730 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8731 if (!dof) continue; 8732 for (s = 0; s < q; ++s) 8733 if (fpoints[p] == ftotpoints[s * 2]) break; 8734 if (s < q) continue; 8735 ftotpoints[q * 2] = fpoints[p]; 8736 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8737 ++q; 8738 } 8739 } 8740 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8741 } 8742 numFPoints = q; 8743 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8744 PetscInt fdof; 8745 8746 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8747 if (!dof) continue; 8748 for (f = 0; f < numFields; ++f) { 8749 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8750 foffsets[f + 1] += fdof; 8751 } 8752 numFIndices += dof; 8753 } 8754 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8755 8756 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8757 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8758 if (numFields) { 8759 const PetscInt **permsF[32] = {NULL}; 8760 const PetscInt **permsC[32] = {NULL}; 8761 8762 for (f = 0; f < numFields; f++) { 8763 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8764 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8765 } 8766 for (p = 0; p < numFPoints; p++) { 8767 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8768 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8769 } 8770 for (p = 0; p < numCPoints; p++) { 8771 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8772 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8773 } 8774 for (f = 0; f < numFields; f++) { 8775 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8776 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8777 } 8778 } else { 8779 const PetscInt **permsF = NULL; 8780 const PetscInt **permsC = NULL; 8781 8782 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8783 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8784 for (p = 0, off = 0; p < numFPoints; p++) { 8785 const PetscInt *perm = permsF ? permsF[p] : NULL; 8786 8787 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8788 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8789 } 8790 for (p = 0, off = 0; p < numCPoints; p++) { 8791 const PetscInt *perm = permsC ? permsC[p] : NULL; 8792 8793 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8794 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8795 } 8796 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8797 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8798 } 8799 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8800 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8801 PetscFunctionReturn(PETSC_SUCCESS); 8802 } 8803 8804 /*@ 8805 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8806 8807 Input Parameter: 8808 . dm - The `DMPLEX` object 8809 8810 Output Parameter: 8811 . cellHeight - The height of a cell 8812 8813 Level: developer 8814 8815 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8816 @*/ 8817 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8818 { 8819 DM_Plex *mesh = (DM_Plex *)dm->data; 8820 8821 PetscFunctionBegin; 8822 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8823 PetscAssertPointer(cellHeight, 2); 8824 *cellHeight = mesh->vtkCellHeight; 8825 PetscFunctionReturn(PETSC_SUCCESS); 8826 } 8827 8828 /*@ 8829 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8830 8831 Input Parameters: 8832 + dm - The `DMPLEX` object 8833 - cellHeight - The height of a cell 8834 8835 Level: developer 8836 8837 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8838 @*/ 8839 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8840 { 8841 DM_Plex *mesh = (DM_Plex *)dm->data; 8842 8843 PetscFunctionBegin; 8844 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8845 mesh->vtkCellHeight = cellHeight; 8846 PetscFunctionReturn(PETSC_SUCCESS); 8847 } 8848 8849 /*@ 8850 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8851 8852 Input Parameters: 8853 + dm - The `DMPLEX` object 8854 - ct - The `DMPolytopeType` of the cell 8855 8856 Output Parameters: 8857 + start - The first cell of this type, or `NULL` 8858 - end - The upper bound on this celltype, or `NULL` 8859 8860 Level: advanced 8861 8862 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8863 @*/ 8864 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end) 8865 { 8866 DM_Plex *mesh = (DM_Plex *)dm->data; 8867 DMLabel label; 8868 PetscInt pStart, pEnd; 8869 8870 PetscFunctionBegin; 8871 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8872 if (start) { 8873 PetscAssertPointer(start, 3); 8874 *start = 0; 8875 } 8876 if (end) { 8877 PetscAssertPointer(end, 4); 8878 *end = 0; 8879 } 8880 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8881 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8882 if (mesh->tr) { 8883 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8884 } else { 8885 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8886 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8887 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8888 } 8889 PetscFunctionReturn(PETSC_SUCCESS); 8890 } 8891 8892 /*@ 8893 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8894 8895 Input Parameters: 8896 + dm - The `DMPLEX` object 8897 - depth - The depth for the given point stratum 8898 8899 Output Parameter: 8900 . gsize - The global number of points in the stratum 8901 8902 Level: advanced 8903 8904 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8905 @*/ 8906 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8907 { 8908 PetscSF sf; 8909 const PetscInt *leaves; 8910 PetscInt Nl, loc, start, end, lsize = 0; 8911 8912 PetscFunctionBegin; 8913 PetscCall(DMGetPointSF(dm, &sf)); 8914 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8915 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8916 for (PetscInt p = start; p < end; ++p) { 8917 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8918 if (loc < 0) ++lsize; 8919 } 8920 PetscCallMPI(MPIU_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8921 PetscFunctionReturn(PETSC_SUCCESS); 8922 } 8923 8924 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8925 { 8926 PetscSection section, globalSection; 8927 PetscInt *numbers, p; 8928 8929 PetscFunctionBegin; 8930 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8931 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8932 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8933 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8934 PetscCall(PetscSectionSetUp(section)); 8935 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8936 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8937 for (p = pStart; p < pEnd; ++p) { 8938 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8939 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8940 else numbers[p - pStart] += shift; 8941 } 8942 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8943 if (globalSize) { 8944 PetscLayout layout; 8945 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8946 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8947 PetscCall(PetscLayoutDestroy(&layout)); 8948 } 8949 PetscCall(PetscSectionDestroy(§ion)); 8950 PetscCall(PetscSectionDestroy(&globalSection)); 8951 PetscFunctionReturn(PETSC_SUCCESS); 8952 } 8953 8954 /*@ 8955 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8956 8957 Input Parameters: 8958 + dm - The `DMPLEX` object 8959 - includeAll - Whether to include all cells, or just the simplex and box cells 8960 8961 Output Parameter: 8962 . globalCellNumbers - Global cell numbers for all cells on this process 8963 8964 Level: developer 8965 8966 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8967 @*/ 8968 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8969 { 8970 PetscInt cellHeight, cStart, cEnd; 8971 8972 PetscFunctionBegin; 8973 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8974 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8975 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8976 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8977 PetscFunctionReturn(PETSC_SUCCESS); 8978 } 8979 8980 /*@ 8981 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8982 8983 Input Parameter: 8984 . dm - The `DMPLEX` object 8985 8986 Output Parameter: 8987 . globalCellNumbers - Global cell numbers for all cells on this process 8988 8989 Level: developer 8990 8991 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8992 @*/ 8993 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8994 { 8995 DM_Plex *mesh = (DM_Plex *)dm->data; 8996 8997 PetscFunctionBegin; 8998 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8999 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 9000 *globalCellNumbers = mesh->globalCellNumbers; 9001 PetscFunctionReturn(PETSC_SUCCESS); 9002 } 9003 9004 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 9005 { 9006 PetscInt vStart, vEnd; 9007 9008 PetscFunctionBegin; 9009 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9010 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9011 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 9012 PetscFunctionReturn(PETSC_SUCCESS); 9013 } 9014 9015 /*@ 9016 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 9017 9018 Input Parameter: 9019 . dm - The `DMPLEX` object 9020 9021 Output Parameter: 9022 . globalVertexNumbers - Global vertex numbers for all vertices on this process 9023 9024 Level: developer 9025 9026 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9027 @*/ 9028 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 9029 { 9030 DM_Plex *mesh = (DM_Plex *)dm->data; 9031 9032 PetscFunctionBegin; 9033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9034 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 9035 *globalVertexNumbers = mesh->globalVertexNumbers; 9036 PetscFunctionReturn(PETSC_SUCCESS); 9037 } 9038 9039 /*@ 9040 DMPlexCreatePointNumbering - Create a global numbering for all points. 9041 9042 Collective 9043 9044 Input Parameter: 9045 . dm - The `DMPLEX` object 9046 9047 Output Parameter: 9048 . globalPointNumbers - Global numbers for all points on this process 9049 9050 Level: developer 9051 9052 Notes: 9053 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 9054 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 9055 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 9056 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 9057 9058 The partitioned mesh is 9059 ``` 9060 (2)--0--(3)--1--(4) (1)--0--(2) 9061 ``` 9062 and its global numbering is 9063 ``` 9064 (3)--0--(4)--1--(5)--2--(6) 9065 ``` 9066 Then the global numbering is provided as 9067 ``` 9068 [0] Number of indices in set 5 9069 [0] 0 0 9070 [0] 1 1 9071 [0] 2 3 9072 [0] 3 4 9073 [0] 4 -6 9074 [1] Number of indices in set 3 9075 [1] 0 2 9076 [1] 1 5 9077 [1] 2 6 9078 ``` 9079 9080 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9081 @*/ 9082 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 9083 { 9084 IS nums[4]; 9085 PetscInt depths[4], gdepths[4], starts[4]; 9086 PetscInt depth, d, shift = 0; 9087 PetscBool empty = PETSC_FALSE; 9088 9089 PetscFunctionBegin; 9090 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9091 PetscCall(DMPlexGetDepth(dm, &depth)); 9092 // For unstratified meshes use dim instead of depth 9093 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9094 // If any stratum is empty, we must mark all empty 9095 for (d = 0; d <= depth; ++d) { 9096 PetscInt end; 9097 9098 depths[d] = depth - d; 9099 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9100 if (!(starts[d] - end)) empty = PETSC_TRUE; 9101 } 9102 if (empty) 9103 for (d = 0; d <= depth; ++d) { 9104 depths[d] = -1; 9105 starts[d] = -1; 9106 } 9107 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9108 PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9109 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]); 9110 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9111 for (d = 0; d <= depth; ++d) { 9112 PetscInt pStart, pEnd, gsize; 9113 9114 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9115 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9116 shift += gsize; 9117 } 9118 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9119 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9120 PetscFunctionReturn(PETSC_SUCCESS); 9121 } 9122 9123 /*@ 9124 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9125 9126 Collective 9127 9128 Input Parameter: 9129 . dm - The `DMPLEX` object 9130 9131 Output Parameter: 9132 . globalEdgeNumbers - Global numbers for all edges on this process 9133 9134 Level: developer 9135 9136 Notes: 9137 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). 9138 9139 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9140 @*/ 9141 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9142 { 9143 PetscSF sf; 9144 PetscInt eStart, eEnd; 9145 9146 PetscFunctionBegin; 9147 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9148 PetscCall(DMGetPointSF(dm, &sf)); 9149 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9150 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9151 PetscFunctionReturn(PETSC_SUCCESS); 9152 } 9153 9154 /*@ 9155 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9156 9157 Input Parameter: 9158 . dm - The `DMPLEX` object 9159 9160 Output Parameter: 9161 . ranks - The rank field 9162 9163 Options Database Key: 9164 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9165 9166 Level: intermediate 9167 9168 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9169 @*/ 9170 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9171 { 9172 DM rdm; 9173 PetscFE fe; 9174 PetscScalar *r; 9175 PetscMPIInt rank; 9176 DMPolytopeType ct; 9177 PetscInt dim, cStart, cEnd, c; 9178 PetscBool simplex; 9179 9180 PetscFunctionBeginUser; 9181 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9182 PetscAssertPointer(ranks, 2); 9183 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9184 PetscCall(DMClone(dm, &rdm)); 9185 PetscCall(DMGetDimension(rdm, &dim)); 9186 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9187 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9188 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9189 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9190 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9191 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9192 PetscCall(PetscFEDestroy(&fe)); 9193 PetscCall(DMCreateDS(rdm)); 9194 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9195 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9196 PetscCall(VecGetArray(*ranks, &r)); 9197 for (c = cStart; c < cEnd; ++c) { 9198 PetscScalar *lr; 9199 9200 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9201 if (lr) *lr = rank; 9202 } 9203 PetscCall(VecRestoreArray(*ranks, &r)); 9204 PetscCall(DMDestroy(&rdm)); 9205 PetscFunctionReturn(PETSC_SUCCESS); 9206 } 9207 9208 /*@ 9209 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9210 9211 Input Parameters: 9212 + dm - The `DMPLEX` 9213 - label - The `DMLabel` 9214 9215 Output Parameter: 9216 . val - The label value field 9217 9218 Options Database Key: 9219 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9220 9221 Level: intermediate 9222 9223 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9224 @*/ 9225 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9226 { 9227 DM rdm, plex; 9228 Vec lval; 9229 PetscSection section; 9230 PetscFE fe; 9231 PetscScalar *v; 9232 PetscInt dim, pStart, pEnd, p, cStart; 9233 DMPolytopeType ct; 9234 char name[PETSC_MAX_PATH_LEN]; 9235 const char *lname, *prefix; 9236 9237 PetscFunctionBeginUser; 9238 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9239 PetscAssertPointer(label, 2); 9240 PetscAssertPointer(val, 3); 9241 PetscCall(DMClone(dm, &rdm)); 9242 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9243 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9244 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9245 PetscCall(DMDestroy(&plex)); 9246 PetscCall(DMGetDimension(rdm, &dim)); 9247 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9248 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9249 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9250 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9251 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9252 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9253 PetscCall(PetscFEDestroy(&fe)); 9254 PetscCall(DMCreateDS(rdm)); 9255 PetscCall(DMCreateGlobalVector(rdm, val)); 9256 PetscCall(DMCreateLocalVector(rdm, &lval)); 9257 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9258 PetscCall(DMGetLocalSection(rdm, §ion)); 9259 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9260 PetscCall(VecGetArray(lval, &v)); 9261 for (p = pStart; p < pEnd; ++p) { 9262 PetscInt cval, dof, off; 9263 9264 PetscCall(PetscSectionGetDof(section, p, &dof)); 9265 if (!dof) continue; 9266 PetscCall(DMLabelGetValue(label, p, &cval)); 9267 PetscCall(PetscSectionGetOffset(section, p, &off)); 9268 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9269 } 9270 PetscCall(VecRestoreArray(lval, &v)); 9271 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9272 PetscCall(VecDestroy(&lval)); 9273 PetscCall(DMDestroy(&rdm)); 9274 PetscFunctionReturn(PETSC_SUCCESS); 9275 } 9276 9277 /*@ 9278 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9279 9280 Input Parameter: 9281 . dm - The `DMPLEX` object 9282 9283 Level: developer 9284 9285 Notes: 9286 This is a useful diagnostic when creating meshes programmatically. 9287 9288 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9289 9290 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9291 @*/ 9292 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9293 { 9294 PetscSection coneSection, supportSection; 9295 const PetscInt *cone, *support; 9296 PetscInt coneSize, c, supportSize, s; 9297 PetscInt pStart, pEnd, p, pp, csize, ssize; 9298 PetscBool storagecheck = PETSC_TRUE; 9299 9300 PetscFunctionBegin; 9301 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9302 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9303 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9304 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9305 /* Check that point p is found in the support of its cone points, and vice versa */ 9306 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9307 for (p = pStart; p < pEnd; ++p) { 9308 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9309 PetscCall(DMPlexGetCone(dm, p, &cone)); 9310 for (c = 0; c < coneSize; ++c) { 9311 PetscBool dup = PETSC_FALSE; 9312 PetscInt d; 9313 for (d = c - 1; d >= 0; --d) { 9314 if (cone[c] == cone[d]) { 9315 dup = PETSC_TRUE; 9316 break; 9317 } 9318 } 9319 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9320 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9321 for (s = 0; s < supportSize; ++s) { 9322 if (support[s] == p) break; 9323 } 9324 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9325 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9326 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9327 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9328 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9329 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9330 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9331 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]); 9332 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9333 } 9334 } 9335 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9336 if (p != pp) { 9337 storagecheck = PETSC_FALSE; 9338 continue; 9339 } 9340 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9341 PetscCall(DMPlexGetSupport(dm, p, &support)); 9342 for (s = 0; s < supportSize; ++s) { 9343 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9344 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9345 for (c = 0; c < coneSize; ++c) { 9346 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9347 if (cone[c] != pp) { 9348 c = 0; 9349 break; 9350 } 9351 if (cone[c] == p) break; 9352 } 9353 if (c >= coneSize) { 9354 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9355 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9356 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9357 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9358 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9359 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9360 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9361 } 9362 } 9363 } 9364 if (storagecheck) { 9365 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9366 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9367 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9368 } 9369 PetscFunctionReturn(PETSC_SUCCESS); 9370 } 9371 9372 /* 9373 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. 9374 */ 9375 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9376 { 9377 DMPolytopeType cct; 9378 PetscInt ptpoints[4]; 9379 const PetscInt *cone, *ccone, *ptcone; 9380 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9381 9382 PetscFunctionBegin; 9383 *unsplit = 0; 9384 switch (ct) { 9385 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9386 ptpoints[npt++] = c; 9387 break; 9388 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9389 PetscCall(DMPlexGetCone(dm, c, &cone)); 9390 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9391 for (cp = 0; cp < coneSize; ++cp) { 9392 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9393 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9394 } 9395 break; 9396 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9397 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9398 PetscCall(DMPlexGetCone(dm, c, &cone)); 9399 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9400 for (cp = 0; cp < coneSize; ++cp) { 9401 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9402 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9403 for (ccp = 0; ccp < cconeSize; ++ccp) { 9404 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9405 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9406 PetscInt p; 9407 for (p = 0; p < npt; ++p) 9408 if (ptpoints[p] == ccone[ccp]) break; 9409 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9410 } 9411 } 9412 } 9413 break; 9414 default: 9415 break; 9416 } 9417 for (pt = 0; pt < npt; ++pt) { 9418 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9419 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9420 } 9421 PetscFunctionReturn(PETSC_SUCCESS); 9422 } 9423 9424 /*@ 9425 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9426 9427 Input Parameters: 9428 + dm - The `DMPLEX` object 9429 - cellHeight - Normally 0 9430 9431 Level: developer 9432 9433 Notes: 9434 This is a useful diagnostic when creating meshes programmatically. 9435 Currently applicable only to homogeneous simplex or tensor meshes. 9436 9437 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9438 9439 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9440 @*/ 9441 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9442 { 9443 DMPlexInterpolatedFlag interp; 9444 DMPolytopeType ct; 9445 PetscInt vStart, vEnd, cStart, cEnd, c; 9446 9447 PetscFunctionBegin; 9448 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9449 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9450 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9451 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9452 for (c = cStart; c < cEnd; ++c) { 9453 PetscInt *closure = NULL; 9454 PetscInt coneSize, closureSize, cl, Nv = 0; 9455 9456 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9457 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9458 if (interp == DMPLEX_INTERPOLATED_FULL) { 9459 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9460 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)); 9461 } 9462 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9463 for (cl = 0; cl < closureSize * 2; cl += 2) { 9464 const PetscInt p = closure[cl]; 9465 if ((p >= vStart) && (p < vEnd)) ++Nv; 9466 } 9467 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9468 /* Special Case: Tensor faces with identified vertices */ 9469 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9470 PetscInt unsplit; 9471 9472 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9473 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9474 } 9475 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)); 9476 } 9477 PetscFunctionReturn(PETSC_SUCCESS); 9478 } 9479 9480 /*@ 9481 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9482 9483 Collective 9484 9485 Input Parameters: 9486 + dm - The `DMPLEX` object 9487 - cellHeight - Normally 0 9488 9489 Level: developer 9490 9491 Notes: 9492 This is a useful diagnostic when creating meshes programmatically. 9493 This routine is only relevant for meshes that are fully interpolated across all ranks. 9494 It will error out if a partially interpolated mesh is given on some rank. 9495 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9496 9497 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9498 9499 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9500 @*/ 9501 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9502 { 9503 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9504 DMPlexInterpolatedFlag interpEnum; 9505 9506 PetscFunctionBegin; 9507 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9508 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9509 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9510 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9511 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9512 PetscFunctionReturn(PETSC_SUCCESS); 9513 } 9514 9515 PetscCall(DMGetDimension(dm, &dim)); 9516 PetscCall(DMPlexGetDepth(dm, &depth)); 9517 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9518 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9519 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9520 for (c = cStart; c < cEnd; ++c) { 9521 const PetscInt *cone, *ornt, *faceSizes, *faces; 9522 const DMPolytopeType *faceTypes; 9523 DMPolytopeType ct; 9524 PetscInt numFaces, coneSize, f; 9525 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9526 9527 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9528 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9529 if (unsplit) continue; 9530 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9531 PetscCall(DMPlexGetCone(dm, c, &cone)); 9532 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9533 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9534 for (cl = 0; cl < closureSize * 2; cl += 2) { 9535 const PetscInt p = closure[cl]; 9536 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9537 } 9538 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9539 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); 9540 for (f = 0; f < numFaces; ++f) { 9541 DMPolytopeType fct; 9542 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9543 9544 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9545 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9546 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9547 const PetscInt p = fclosure[cl]; 9548 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9549 } 9550 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]); 9551 for (v = 0; v < fnumCorners; ++v) { 9552 if (fclosure[v] != faces[fOff + v]) { 9553 PetscInt v1; 9554 9555 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9556 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9557 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9558 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9559 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9560 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]); 9561 } 9562 } 9563 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9564 fOff += faceSizes[f]; 9565 } 9566 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9567 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9568 } 9569 } 9570 PetscFunctionReturn(PETSC_SUCCESS); 9571 } 9572 9573 /*@ 9574 DMPlexCheckGeometry - Check the geometry of mesh cells 9575 9576 Input Parameter: 9577 . dm - The `DMPLEX` object 9578 9579 Level: developer 9580 9581 Notes: 9582 This is a useful diagnostic when creating meshes programmatically. 9583 9584 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9585 9586 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9587 @*/ 9588 PetscErrorCode DMPlexCheckGeometry(DM dm) 9589 { 9590 Vec coordinates; 9591 PetscReal detJ, J[9], refVol = 1.0; 9592 PetscReal vol; 9593 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9594 9595 PetscFunctionBegin; 9596 PetscCall(DMGetDimension(dm, &dim)); 9597 PetscCall(DMGetCoordinateDim(dm, &dE)); 9598 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9599 PetscCall(DMPlexGetDepth(dm, &depth)); 9600 for (d = 0; d < dim; ++d) refVol *= 2.0; 9601 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9602 /* Make sure local coordinates are created, because that step is collective */ 9603 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9604 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9605 for (c = cStart; c < cEnd; ++c) { 9606 DMPolytopeType ct; 9607 PetscInt unsplit; 9608 PetscBool ignoreZeroVol = PETSC_FALSE; 9609 9610 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9611 switch (ct) { 9612 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9613 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9614 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9615 ignoreZeroVol = PETSC_TRUE; 9616 break; 9617 default: 9618 break; 9619 } 9620 switch (ct) { 9621 case DM_POLYTOPE_TRI_PRISM: 9622 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9623 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9624 case DM_POLYTOPE_PYRAMID: 9625 continue; 9626 default: 9627 break; 9628 } 9629 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9630 if (unsplit) continue; 9631 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9632 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); 9633 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9634 /* This should work with periodicity since DG coordinates should be used */ 9635 if (depth > 1) { 9636 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9637 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); 9638 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9639 } 9640 } 9641 PetscFunctionReturn(PETSC_SUCCESS); 9642 } 9643 9644 /*@ 9645 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9646 9647 Collective 9648 9649 Input Parameters: 9650 + dm - The `DMPLEX` object 9651 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9652 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9653 9654 Level: developer 9655 9656 Notes: 9657 This is mainly intended for debugging/testing purposes. 9658 9659 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9660 9661 Extra roots can come from periodic cuts, where additional points appear on the boundary 9662 9663 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9664 @*/ 9665 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9666 { 9667 PetscInt l, nleaves, nroots, overlap; 9668 const PetscInt *locals; 9669 const PetscSFNode *remotes; 9670 PetscBool distributed; 9671 MPI_Comm comm; 9672 PetscMPIInt rank; 9673 9674 PetscFunctionBegin; 9675 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9676 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9677 else pointSF = dm->sf; 9678 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9679 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9680 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9681 { 9682 PetscMPIInt mpiFlag; 9683 9684 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9685 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9686 } 9687 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9688 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9689 if (!distributed) { 9690 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); 9691 PetscFunctionReturn(PETSC_SUCCESS); 9692 } 9693 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); 9694 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9695 9696 /* Check SF graph is compatible with DMPlex chart */ 9697 { 9698 PetscInt pStart, pEnd, maxLeaf; 9699 9700 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9701 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9702 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9703 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9704 } 9705 9706 /* Check there are no cells in interface */ 9707 if (!overlap) { 9708 PetscInt cellHeight, cStart, cEnd; 9709 9710 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9711 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9712 for (l = 0; l < nleaves; ++l) { 9713 const PetscInt point = locals ? locals[l] : l; 9714 9715 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9716 } 9717 } 9718 9719 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9720 { 9721 const PetscInt *rootdegree; 9722 9723 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9724 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9725 for (l = 0; l < nleaves; ++l) { 9726 const PetscInt point = locals ? locals[l] : l; 9727 const PetscInt *cone; 9728 PetscInt coneSize, c, idx; 9729 9730 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9731 PetscCall(DMPlexGetCone(dm, point, &cone)); 9732 for (c = 0; c < coneSize; ++c) { 9733 if (!rootdegree[cone[c]]) { 9734 if (locals) { 9735 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9736 } else { 9737 idx = (cone[c] < nleaves) ? cone[c] : -1; 9738 } 9739 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9740 } 9741 } 9742 } 9743 } 9744 PetscFunctionReturn(PETSC_SUCCESS); 9745 } 9746 9747 /*@ 9748 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9749 9750 Collective 9751 9752 Input Parameter: 9753 . dm - The `DMPLEX` object 9754 9755 Level: developer 9756 9757 Notes: 9758 This is mainly intended for debugging/testing purposes. 9759 9760 Other cell types which are disconnected would be caught by the symmetry and face checks. 9761 9762 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9763 9764 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9765 @*/ 9766 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9767 { 9768 PetscInt pStart, pEnd, vStart, vEnd; 9769 9770 PetscFunctionBegin; 9771 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9772 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9773 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9774 for (PetscInt v = vStart; v < vEnd; ++v) { 9775 PetscInt suppSize; 9776 9777 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9778 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9779 } 9780 PetscFunctionReturn(PETSC_SUCCESS); 9781 } 9782 9783 /*@ 9784 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9785 9786 Input Parameter: 9787 . dm - The `DMPLEX` object 9788 9789 Level: developer 9790 9791 Notes: 9792 This is a useful diagnostic when creating meshes programmatically. 9793 9794 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9795 9796 Currently does not include `DMPlexCheckCellShape()`. 9797 9798 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9799 @*/ 9800 PetscErrorCode DMPlexCheck(DM dm) 9801 { 9802 PetscInt cellHeight; 9803 9804 PetscFunctionBegin; 9805 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9806 PetscCall(DMPlexCheckSymmetry(dm)); 9807 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9808 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9809 PetscCall(DMPlexCheckGeometry(dm)); 9810 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9811 PetscCall(DMPlexCheckInterfaceCones(dm)); 9812 PetscCall(DMPlexCheckOrphanVertices(dm)); 9813 PetscFunctionReturn(PETSC_SUCCESS); 9814 } 9815 9816 typedef struct cell_stats { 9817 PetscReal min, max, sum, squaresum; 9818 PetscInt count; 9819 } cell_stats_t; 9820 9821 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9822 { 9823 PetscInt i, N = *len; 9824 9825 for (i = 0; i < N; i++) { 9826 cell_stats_t *A = (cell_stats_t *)a; 9827 cell_stats_t *B = (cell_stats_t *)b; 9828 9829 B->min = PetscMin(A->min, B->min); 9830 B->max = PetscMax(A->max, B->max); 9831 B->sum += A->sum; 9832 B->squaresum += A->squaresum; 9833 B->count += A->count; 9834 } 9835 } 9836 9837 /*@ 9838 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9839 9840 Collective 9841 9842 Input Parameters: 9843 + dm - The `DMPLEX` object 9844 . output - If true, statistics will be displayed on `stdout` 9845 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9846 9847 Level: developer 9848 9849 Notes: 9850 This is mainly intended for debugging/testing purposes. 9851 9852 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9853 9854 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9855 @*/ 9856 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9857 { 9858 DM dmCoarse; 9859 cell_stats_t stats, globalStats; 9860 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9861 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9862 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9863 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9864 PetscMPIInt rank, size; 9865 9866 PetscFunctionBegin; 9867 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9868 stats.min = PETSC_MAX_REAL; 9869 stats.max = PETSC_MIN_REAL; 9870 stats.sum = stats.squaresum = 0.; 9871 stats.count = 0; 9872 9873 PetscCallMPI(MPI_Comm_size(comm, &size)); 9874 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9875 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9876 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9877 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9878 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9879 for (c = cStart; c < cEnd; c++) { 9880 PetscInt i; 9881 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9882 9883 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9884 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9885 for (i = 0; i < PetscSqr(cdim); ++i) { 9886 frobJ += J[i] * J[i]; 9887 frobInvJ += invJ[i] * invJ[i]; 9888 } 9889 cond2 = frobJ * frobInvJ; 9890 cond = PetscSqrtReal(cond2); 9891 9892 stats.min = PetscMin(stats.min, cond); 9893 stats.max = PetscMax(stats.max, cond); 9894 stats.sum += cond; 9895 stats.squaresum += cond2; 9896 stats.count++; 9897 if (output && cond > limit) { 9898 PetscSection coordSection; 9899 Vec coordsLocal; 9900 PetscScalar *coords = NULL; 9901 PetscInt Nv, d, clSize, cl, *closure = NULL; 9902 9903 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9904 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9905 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9906 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9907 for (i = 0; i < Nv / cdim; ++i) { 9908 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9909 for (d = 0; d < cdim; ++d) { 9910 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9911 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9912 } 9913 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9914 } 9915 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9916 for (cl = 0; cl < clSize * 2; cl += 2) { 9917 const PetscInt edge = closure[cl]; 9918 9919 if ((edge >= eStart) && (edge < eEnd)) { 9920 PetscReal len; 9921 9922 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9923 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9924 } 9925 } 9926 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9927 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9928 } 9929 } 9930 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9931 9932 if (size > 1) { 9933 PetscMPIInt blockLengths[2] = {4, 1}; 9934 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9935 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9936 MPI_Op statReduce; 9937 9938 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9939 PetscCallMPI(MPI_Type_commit(&statType)); 9940 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9941 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9942 PetscCallMPI(MPI_Op_free(&statReduce)); 9943 PetscCallMPI(MPI_Type_free(&statType)); 9944 } else { 9945 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9946 } 9947 if (rank == 0) { 9948 count = globalStats.count; 9949 min = globalStats.min; 9950 max = globalStats.max; 9951 mean = globalStats.sum / globalStats.count; 9952 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9953 } 9954 9955 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)); 9956 PetscCall(PetscFree2(J, invJ)); 9957 9958 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9959 if (dmCoarse) { 9960 PetscBool isplex; 9961 9962 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9963 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9964 } 9965 PetscFunctionReturn(PETSC_SUCCESS); 9966 } 9967 9968 /*@ 9969 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9970 orthogonal quality below given tolerance. 9971 9972 Collective 9973 9974 Input Parameters: 9975 + dm - The `DMPLEX` object 9976 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9977 - atol - [0, 1] Absolute tolerance for tagging cells. 9978 9979 Output Parameters: 9980 + OrthQual - `Vec` containing orthogonal quality per cell 9981 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9982 9983 Options Database Keys: 9984 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9985 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9986 9987 Level: intermediate 9988 9989 Notes: 9990 Orthogonal quality is given by the following formula\: 9991 9992 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9993 9994 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 9995 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9996 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9997 calculating the cosine of the angle between these vectors. 9998 9999 Orthogonal quality ranges from 1 (best) to 0 (worst). 10000 10001 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 10002 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 10003 10004 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 10005 10006 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 10007 @*/ 10008 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 10009 { 10010 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 10011 PetscInt *idx; 10012 PetscScalar *oqVals; 10013 const PetscScalar *cellGeomArr, *faceGeomArr; 10014 PetscReal *ci, *fi, *Ai; 10015 MPI_Comm comm; 10016 Vec cellgeom, facegeom; 10017 DM dmFace, dmCell; 10018 IS glob; 10019 ISLocalToGlobalMapping ltog; 10020 PetscViewer vwr; 10021 10022 PetscFunctionBegin; 10023 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10024 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 10025 PetscAssertPointer(OrthQual, 4); 10026 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 10027 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 10028 PetscCall(DMGetDimension(dm, &nc)); 10029 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 10030 { 10031 DMPlexInterpolatedFlag interpFlag; 10032 10033 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 10034 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 10035 PetscMPIInt rank; 10036 10037 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 10038 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 10039 } 10040 } 10041 if (OrthQualLabel) { 10042 PetscAssertPointer(OrthQualLabel, 5); 10043 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 10044 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 10045 } else { 10046 *OrthQualLabel = NULL; 10047 } 10048 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 10049 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 10050 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 10051 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 10052 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 10053 PetscCall(VecCreate(comm, OrthQual)); 10054 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 10055 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 10056 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 10057 PetscCall(VecSetUp(*OrthQual)); 10058 PetscCall(ISDestroy(&glob)); 10059 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 10060 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 10061 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 10062 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 10063 PetscCall(VecGetDM(cellgeom, &dmCell)); 10064 PetscCall(VecGetDM(facegeom, &dmFace)); 10065 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 10066 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 10067 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 10068 PetscInt cellarr[2], *adj = NULL; 10069 PetscScalar *cArr, *fArr; 10070 PetscReal minvalc = 1.0, minvalf = 1.0; 10071 PetscFVCellGeom *cg; 10072 10073 idx[cellIter] = cell - cStart; 10074 cellarr[0] = cell; 10075 /* Make indexing into cellGeom easier */ 10076 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10077 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10078 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10079 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10080 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10081 PetscInt i; 10082 const PetscInt neigh = adj[cellneigh]; 10083 PetscReal normci = 0, normfi = 0, normai = 0; 10084 PetscFVCellGeom *cgneigh; 10085 PetscFVFaceGeom *fg; 10086 10087 /* Don't count ourselves in the neighbor list */ 10088 if (neigh == cell) continue; 10089 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10090 cellarr[1] = neigh; 10091 { 10092 PetscInt numcovpts; 10093 const PetscInt *covpts; 10094 10095 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10096 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10097 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10098 } 10099 10100 /* Compute c_i, f_i and their norms */ 10101 for (i = 0; i < nc; i++) { 10102 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10103 fi[i] = fg->centroid[i] - cg->centroid[i]; 10104 Ai[i] = fg->normal[i]; 10105 normci += PetscPowReal(ci[i], 2); 10106 normfi += PetscPowReal(fi[i], 2); 10107 normai += PetscPowReal(Ai[i], 2); 10108 } 10109 normci = PetscSqrtReal(normci); 10110 normfi = PetscSqrtReal(normfi); 10111 normai = PetscSqrtReal(normai); 10112 10113 /* Normalize and compute for each face-cell-normal pair */ 10114 for (i = 0; i < nc; i++) { 10115 ci[i] = ci[i] / normci; 10116 fi[i] = fi[i] / normfi; 10117 Ai[i] = Ai[i] / normai; 10118 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10119 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10120 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10121 } 10122 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10123 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10124 } 10125 PetscCall(PetscFree(adj)); 10126 PetscCall(PetscFree2(cArr, fArr)); 10127 /* Defer to cell if they're equal */ 10128 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10129 if (OrthQualLabel) { 10130 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10131 } 10132 } 10133 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10134 PetscCall(VecAssemblyBegin(*OrthQual)); 10135 PetscCall(VecAssemblyEnd(*OrthQual)); 10136 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10137 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10138 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10139 if (OrthQualLabel) { 10140 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10141 } 10142 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10143 PetscCall(PetscViewerDestroy(&vwr)); 10144 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10145 PetscFunctionReturn(PETSC_SUCCESS); 10146 } 10147 10148 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10149 * interpolator construction */ 10150 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10151 { 10152 PetscSection section, newSection, gsection; 10153 PetscSF sf; 10154 PetscBool hasConstraints, ghasConstraints; 10155 10156 PetscFunctionBegin; 10157 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10158 PetscAssertPointer(odm, 2); 10159 PetscCall(DMGetLocalSection(dm, §ion)); 10160 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10161 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10162 if (!ghasConstraints) { 10163 PetscCall(PetscObjectReference((PetscObject)dm)); 10164 *odm = dm; 10165 PetscFunctionReturn(PETSC_SUCCESS); 10166 } 10167 PetscCall(DMClone(dm, odm)); 10168 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10169 PetscCall(DMGetLocalSection(*odm, &newSection)); 10170 PetscCall(DMGetPointSF(*odm, &sf)); 10171 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10172 PetscCall(DMSetGlobalSection(*odm, gsection)); 10173 PetscCall(PetscSectionDestroy(&gsection)); 10174 PetscFunctionReturn(PETSC_SUCCESS); 10175 } 10176 10177 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10178 { 10179 DM dmco, dmfo; 10180 Mat interpo; 10181 Vec rscale; 10182 Vec cglobalo, clocal; 10183 Vec fglobal, fglobalo, flocal; 10184 PetscBool regular; 10185 10186 PetscFunctionBegin; 10187 PetscCall(DMGetFullDM(dmc, &dmco)); 10188 PetscCall(DMGetFullDM(dmf, &dmfo)); 10189 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10190 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10191 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10192 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10193 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10194 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10195 PetscCall(VecSet(cglobalo, 0.)); 10196 PetscCall(VecSet(clocal, 0.)); 10197 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10198 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10199 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10200 PetscCall(VecSet(fglobal, 0.)); 10201 PetscCall(VecSet(fglobalo, 0.)); 10202 PetscCall(VecSet(flocal, 0.)); 10203 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10204 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10205 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10206 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10207 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10208 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10209 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10210 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10211 *shift = fglobal; 10212 PetscCall(VecDestroy(&flocal)); 10213 PetscCall(VecDestroy(&fglobalo)); 10214 PetscCall(VecDestroy(&clocal)); 10215 PetscCall(VecDestroy(&cglobalo)); 10216 PetscCall(VecDestroy(&rscale)); 10217 PetscCall(MatDestroy(&interpo)); 10218 PetscCall(DMDestroy(&dmfo)); 10219 PetscCall(DMDestroy(&dmco)); 10220 PetscFunctionReturn(PETSC_SUCCESS); 10221 } 10222 10223 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10224 { 10225 PetscObject shifto; 10226 Vec shift; 10227 10228 PetscFunctionBegin; 10229 if (!interp) { 10230 Vec rscale; 10231 10232 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10233 PetscCall(VecDestroy(&rscale)); 10234 } else { 10235 PetscCall(PetscObjectReference((PetscObject)interp)); 10236 } 10237 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10238 if (!shifto) { 10239 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10240 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10241 shifto = (PetscObject)shift; 10242 PetscCall(VecDestroy(&shift)); 10243 } 10244 shift = (Vec)shifto; 10245 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10246 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10247 PetscCall(MatDestroy(&interp)); 10248 PetscFunctionReturn(PETSC_SUCCESS); 10249 } 10250 10251 /* Pointwise interpolation 10252 Just code FEM for now 10253 u^f = I u^c 10254 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10255 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10256 I_{ij} = psi^f_i phi^c_j 10257 */ 10258 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10259 { 10260 PetscSection gsc, gsf; 10261 PetscInt m, n; 10262 void *ctx; 10263 DM cdm; 10264 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10265 10266 PetscFunctionBegin; 10267 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10268 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10269 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10270 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10271 10272 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10273 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10274 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10275 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10276 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10277 10278 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10279 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10280 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10281 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10282 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10283 if (scaling) { 10284 /* Use naive scaling */ 10285 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10286 } 10287 PetscFunctionReturn(PETSC_SUCCESS); 10288 } 10289 10290 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10291 { 10292 VecScatter ctx; 10293 10294 PetscFunctionBegin; 10295 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10296 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10297 PetscCall(VecScatterDestroy(&ctx)); 10298 PetscFunctionReturn(PETSC_SUCCESS); 10299 } 10300 10301 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[]) 10302 { 10303 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10304 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10305 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10306 } 10307 10308 // The assumption here is that the test field is a vector and the basis field is a scalar (so we need the gradient) 10309 static void g1_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]) 10310 { 10311 for (PetscInt c = 0; c < dim; ++c) g1[c * dim + c] = 1.0; 10312 } 10313 10314 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10315 { 10316 DM dmc; 10317 PetscDS ds; 10318 Vec ones, locmass; 10319 IS cellIS; 10320 PetscFormKey key; 10321 PetscInt depth; 10322 10323 PetscFunctionBegin; 10324 PetscCall(DMClone(dm, &dmc)); 10325 PetscCall(DMCopyDisc(dm, dmc)); 10326 PetscCall(DMGetDS(dmc, &ds)); 10327 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10328 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10329 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10330 else PetscCall(DMGetLocalVector(dm, &locmass)); 10331 PetscCall(DMGetLocalVector(dm, &ones)); 10332 PetscCall(DMPlexGetDepth(dm, &depth)); 10333 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10334 PetscCall(VecSet(locmass, 0.0)); 10335 PetscCall(VecSet(ones, 1.0)); 10336 key.label = NULL; 10337 key.value = 0; 10338 key.field = 0; 10339 key.part = 0; 10340 PetscCall(DMPlexComputeJacobianActionByKey(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10341 PetscCall(ISDestroy(&cellIS)); 10342 if (mass) { 10343 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10344 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10345 } 10346 PetscCall(DMRestoreLocalVector(dm, &ones)); 10347 if (lmass) *lmass = locmass; 10348 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10349 PetscCall(DMDestroy(&dmc)); 10350 PetscFunctionReturn(PETSC_SUCCESS); 10351 } 10352 10353 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10354 { 10355 PetscSection gsc, gsf; 10356 PetscInt m, n; 10357 void *ctx; 10358 DM cdm; 10359 PetscBool regular; 10360 10361 PetscFunctionBegin; 10362 if (dmFine == dmCoarse) { 10363 DM dmc; 10364 PetscDS ds; 10365 PetscWeakForm wf; 10366 Vec u; 10367 IS cellIS; 10368 PetscFormKey key; 10369 PetscInt depth; 10370 10371 PetscCall(DMClone(dmFine, &dmc)); 10372 PetscCall(DMCopyDisc(dmFine, dmc)); 10373 PetscCall(DMGetDS(dmc, &ds)); 10374 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10375 PetscCall(PetscWeakFormClear(wf)); 10376 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10377 PetscCall(DMCreateMatrix(dmc, mass)); 10378 PetscCall(DMGetLocalVector(dmc, &u)); 10379 PetscCall(DMPlexGetDepth(dmc, &depth)); 10380 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10381 PetscCall(MatZeroEntries(*mass)); 10382 key.label = NULL; 10383 key.value = 0; 10384 key.field = 0; 10385 key.part = 0; 10386 PetscCall(DMPlexComputeJacobianByKey(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10387 PetscCall(ISDestroy(&cellIS)); 10388 PetscCall(DMRestoreLocalVector(dmc, &u)); 10389 PetscCall(DMDestroy(&dmc)); 10390 } else { 10391 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10392 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10393 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10394 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10395 10396 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10397 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10398 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10399 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10400 10401 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10402 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10403 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10404 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10405 } 10406 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10407 PetscFunctionReturn(PETSC_SUCCESS); 10408 } 10409 10410 PetscErrorCode DMCreateGradientMatrix_Plex(DM dmc, DM dmr, Mat *derv) 10411 { 10412 PetscSection gsc, gsf; 10413 PetscInt m, n; 10414 void *ctx; 10415 10416 PetscFunctionBegin; 10417 PetscCall(DMGetGlobalSection(dmr, &gsf)); 10418 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10419 PetscCall(DMGetGlobalSection(dmc, &gsc)); 10420 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10421 10422 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmc), derv)); 10423 PetscCall(PetscObjectSetName((PetscObject)*derv, "Plex Derivative Matrix")); 10424 PetscCall(MatSetSizes(*derv, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10425 PetscCall(MatSetType(*derv, dmc->mattype)); 10426 10427 PetscCall(DMGetApplicationContext(dmr, &ctx)); 10428 { 10429 DM ndmr; 10430 PetscDS ds; 10431 PetscWeakForm wf; 10432 Vec u; 10433 IS cellIS; 10434 PetscFormKey key; 10435 PetscInt depth, Nf; 10436 10437 PetscCall(DMClone(dmr, &ndmr)); 10438 PetscCall(DMCopyDisc(dmr, ndmr)); 10439 PetscCall(DMGetDS(ndmr, &ds)); 10440 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10441 PetscCall(PetscWeakFormClear(wf)); 10442 PetscCall(PetscDSGetNumFields(ds, &Nf)); 10443 for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, NULL, g1_identity_private, NULL, NULL)); 10444 PetscCall(DMGetLocalVector(ndmr, &u)); 10445 PetscCall(DMPlexGetDepth(ndmr, &depth)); 10446 PetscCall(DMGetStratumIS(ndmr, "depth", depth, &cellIS)); 10447 PetscCall(MatZeroEntries(*derv)); 10448 key.label = NULL; 10449 key.value = 0; 10450 key.field = 0; 10451 key.part = 0; 10452 PetscCall(DMPlexComputeJacobianByKeyGeneral(ndmr, dmc, key, cellIS, 0.0, 0.0, u, NULL, *derv, *derv, NULL)); 10453 PetscCall(ISDestroy(&cellIS)); 10454 PetscCall(DMRestoreLocalVector(ndmr, &u)); 10455 PetscCall(DMDestroy(&ndmr)); 10456 } 10457 PetscCall(MatViewFromOptions(*derv, NULL, "-gradient_mat_view")); 10458 PetscFunctionReturn(PETSC_SUCCESS); 10459 } 10460 10461 /*@ 10462 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10463 10464 Input Parameter: 10465 . dm - The `DMPLEX` object 10466 10467 Output Parameter: 10468 . regular - The flag 10469 10470 Level: intermediate 10471 10472 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10473 @*/ 10474 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10475 { 10476 PetscFunctionBegin; 10477 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10478 PetscAssertPointer(regular, 2); 10479 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10480 PetscFunctionReturn(PETSC_SUCCESS); 10481 } 10482 10483 /*@ 10484 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10485 10486 Input Parameters: 10487 + dm - The `DMPLEX` object 10488 - regular - The flag 10489 10490 Level: intermediate 10491 10492 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10493 @*/ 10494 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10495 { 10496 PetscFunctionBegin; 10497 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10498 ((DM_Plex *)dm->data)->regularRefinement = regular; 10499 PetscFunctionReturn(PETSC_SUCCESS); 10500 } 10501 10502 /*@ 10503 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10504 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10505 10506 Not Collective 10507 10508 Input Parameter: 10509 . dm - The `DMPLEX` object 10510 10511 Output Parameters: 10512 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10513 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10514 10515 Level: intermediate 10516 10517 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10518 @*/ 10519 PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS) 10520 { 10521 DM_Plex *plex = (DM_Plex *)dm->data; 10522 10523 PetscFunctionBegin; 10524 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10525 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10526 if (anchorSection) *anchorSection = plex->anchorSection; 10527 if (anchorIS) *anchorIS = plex->anchorIS; 10528 PetscFunctionReturn(PETSC_SUCCESS); 10529 } 10530 10531 /*@ 10532 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10533 10534 Collective 10535 10536 Input Parameters: 10537 + dm - The `DMPLEX` object 10538 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10539 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10540 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10541 10542 Level: intermediate 10543 10544 Notes: 10545 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10546 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10547 combination of other points' degrees of freedom. 10548 10549 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10550 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10551 10552 The reference counts of `anchorSection` and `anchorIS` are incremented. 10553 10554 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10555 @*/ 10556 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10557 { 10558 DM_Plex *plex = (DM_Plex *)dm->data; 10559 PetscMPIInt result; 10560 10561 PetscFunctionBegin; 10562 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10563 if (anchorSection) { 10564 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10565 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10566 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10567 } 10568 if (anchorIS) { 10569 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10570 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10571 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10572 } 10573 10574 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10575 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10576 plex->anchorSection = anchorSection; 10577 10578 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10579 PetscCall(ISDestroy(&plex->anchorIS)); 10580 plex->anchorIS = anchorIS; 10581 10582 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10583 PetscInt size, a, pStart, pEnd; 10584 const PetscInt *anchors; 10585 10586 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10587 PetscCall(ISGetLocalSize(anchorIS, &size)); 10588 PetscCall(ISGetIndices(anchorIS, &anchors)); 10589 for (a = 0; a < size; a++) { 10590 PetscInt p; 10591 10592 p = anchors[a]; 10593 if (p >= pStart && p < pEnd) { 10594 PetscInt dof; 10595 10596 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10597 if (dof) { 10598 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10599 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10600 } 10601 } 10602 } 10603 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10604 } 10605 /* reset the generic constraints */ 10606 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10607 PetscFunctionReturn(PETSC_SUCCESS); 10608 } 10609 10610 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10611 { 10612 PetscSection anchorSection; 10613 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10614 10615 PetscFunctionBegin; 10616 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10617 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10618 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10619 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10620 if (numFields) { 10621 PetscInt f; 10622 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10623 10624 for (f = 0; f < numFields; f++) { 10625 PetscInt numComp; 10626 10627 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10628 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10629 } 10630 } 10631 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10632 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10633 pStart = PetscMax(pStart, sStart); 10634 pEnd = PetscMin(pEnd, sEnd); 10635 pEnd = PetscMax(pStart, pEnd); 10636 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10637 for (p = pStart; p < pEnd; p++) { 10638 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10639 if (dof) { 10640 PetscCall(PetscSectionGetDof(section, p, &dof)); 10641 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10642 for (f = 0; f < numFields; f++) { 10643 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10644 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10645 } 10646 } 10647 } 10648 PetscCall(PetscSectionSetUp(*cSec)); 10649 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10650 PetscFunctionReturn(PETSC_SUCCESS); 10651 } 10652 10653 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10654 { 10655 PetscSection aSec; 10656 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10657 const PetscInt *anchors; 10658 PetscInt numFields, f; 10659 IS aIS; 10660 MatType mtype; 10661 PetscBool iscuda, iskokkos; 10662 10663 PetscFunctionBegin; 10664 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10665 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10666 PetscCall(PetscSectionGetStorageSize(section, &n)); 10667 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10668 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10669 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10670 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10671 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10672 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10673 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10674 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10675 else mtype = MATSEQAIJ; 10676 PetscCall(MatSetType(*cMat, mtype)); 10677 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10678 PetscCall(ISGetIndices(aIS, &anchors)); 10679 /* cSec will be a subset of aSec and section */ 10680 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10681 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10682 PetscCall(PetscMalloc1(m + 1, &i)); 10683 i[0] = 0; 10684 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10685 for (p = pStart; p < pEnd; p++) { 10686 PetscInt rDof, rOff, r; 10687 10688 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10689 if (!rDof) continue; 10690 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10691 if (numFields) { 10692 for (f = 0; f < numFields; f++) { 10693 annz = 0; 10694 for (r = 0; r < rDof; r++) { 10695 a = anchors[rOff + r]; 10696 if (a < sStart || a >= sEnd) continue; 10697 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10698 annz += aDof; 10699 } 10700 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10701 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10702 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10703 } 10704 } else { 10705 annz = 0; 10706 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10707 for (q = 0; q < dof; q++) { 10708 a = anchors[rOff + q]; 10709 if (a < sStart || a >= sEnd) continue; 10710 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10711 annz += aDof; 10712 } 10713 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10714 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10715 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10716 } 10717 } 10718 nnz = i[m]; 10719 PetscCall(PetscMalloc1(nnz, &j)); 10720 offset = 0; 10721 for (p = pStart; p < pEnd; p++) { 10722 if (numFields) { 10723 for (f = 0; f < numFields; f++) { 10724 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10725 for (q = 0; q < dof; q++) { 10726 PetscInt rDof, rOff, r; 10727 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10728 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10729 for (r = 0; r < rDof; r++) { 10730 PetscInt s; 10731 10732 a = anchors[rOff + r]; 10733 if (a < sStart || a >= sEnd) continue; 10734 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10735 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10736 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10737 } 10738 } 10739 } 10740 } else { 10741 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10742 for (q = 0; q < dof; q++) { 10743 PetscInt rDof, rOff, r; 10744 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10745 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10746 for (r = 0; r < rDof; r++) { 10747 PetscInt s; 10748 10749 a = anchors[rOff + r]; 10750 if (a < sStart || a >= sEnd) continue; 10751 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10752 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10753 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10754 } 10755 } 10756 } 10757 } 10758 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10759 PetscCall(PetscFree(i)); 10760 PetscCall(PetscFree(j)); 10761 PetscCall(ISRestoreIndices(aIS, &anchors)); 10762 PetscFunctionReturn(PETSC_SUCCESS); 10763 } 10764 10765 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10766 { 10767 DM_Plex *plex = (DM_Plex *)dm->data; 10768 PetscSection anchorSection, section, cSec; 10769 Mat cMat; 10770 10771 PetscFunctionBegin; 10772 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10773 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10774 if (anchorSection) { 10775 PetscInt Nf; 10776 10777 PetscCall(DMGetLocalSection(dm, §ion)); 10778 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10779 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10780 PetscCall(DMGetNumFields(dm, &Nf)); 10781 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10782 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10783 PetscCall(PetscSectionDestroy(&cSec)); 10784 PetscCall(MatDestroy(&cMat)); 10785 } 10786 PetscFunctionReturn(PETSC_SUCCESS); 10787 } 10788 10789 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10790 { 10791 IS subis; 10792 PetscSection section, subsection; 10793 10794 PetscFunctionBegin; 10795 PetscCall(DMGetLocalSection(dm, §ion)); 10796 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10797 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10798 /* Create subdomain */ 10799 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10800 /* Create submodel */ 10801 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10802 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10803 PetscCall(DMSetLocalSection(*subdm, subsection)); 10804 PetscCall(PetscSectionDestroy(&subsection)); 10805 PetscCall(DMCopyDisc(dm, *subdm)); 10806 /* Create map from submodel to global model */ 10807 if (is) { 10808 PetscSection sectionGlobal, subsectionGlobal; 10809 IS spIS; 10810 const PetscInt *spmap; 10811 PetscInt *subIndices; 10812 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10813 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10814 10815 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10816 PetscCall(ISGetIndices(spIS, &spmap)); 10817 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10818 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10819 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10820 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10821 for (p = pStart; p < pEnd; ++p) { 10822 PetscInt gdof, pSubSize = 0; 10823 10824 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10825 if (gdof > 0) { 10826 for (f = 0; f < Nf; ++f) { 10827 PetscInt fdof, fcdof; 10828 10829 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10830 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10831 pSubSize += fdof - fcdof; 10832 } 10833 subSize += pSubSize; 10834 if (pSubSize) { 10835 if (bs < 0) { 10836 bs = pSubSize; 10837 } else if (bs != pSubSize) { 10838 /* Layout does not admit a pointwise block size */ 10839 bs = 1; 10840 } 10841 } 10842 } 10843 } 10844 /* Must have same blocksize on all procs (some might have no points) */ 10845 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10846 bsLocal[1] = bs; 10847 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10848 if (bsMinMax[0] != bsMinMax[1]) { 10849 bs = 1; 10850 } else { 10851 bs = bsMinMax[0]; 10852 } 10853 PetscCall(PetscMalloc1(subSize, &subIndices)); 10854 for (p = pStart; p < pEnd; ++p) { 10855 PetscInt gdof, goff; 10856 10857 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10858 if (gdof > 0) { 10859 const PetscInt point = spmap[p]; 10860 10861 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10862 for (f = 0; f < Nf; ++f) { 10863 PetscInt fdof, fcdof, fc, f2, poff = 0; 10864 10865 /* Can get rid of this loop by storing field information in the global section */ 10866 for (f2 = 0; f2 < f; ++f2) { 10867 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10868 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10869 poff += fdof - fcdof; 10870 } 10871 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10872 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10873 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10874 } 10875 } 10876 } 10877 PetscCall(ISRestoreIndices(spIS, &spmap)); 10878 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10879 if (bs > 1) { 10880 /* We need to check that the block size does not come from non-contiguous fields */ 10881 PetscInt i, j, set = 1; 10882 for (i = 0; i < subSize; i += bs) { 10883 for (j = 0; j < bs; ++j) { 10884 if (subIndices[i + j] != subIndices[i] + j) { 10885 set = 0; 10886 break; 10887 } 10888 } 10889 } 10890 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10891 } 10892 // Attach nullspace 10893 if (dm->nullspaceConstructors) { 10894 for (f = 0; f < Nf; ++f) { 10895 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10896 if ((*subdm)->nullspaceConstructors[f]) break; 10897 } 10898 if (f < Nf) { 10899 MatNullSpace nullSpace; 10900 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10901 10902 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10903 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10904 } 10905 } 10906 } 10907 PetscFunctionReturn(PETSC_SUCCESS); 10908 } 10909 10910 /*@ 10911 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10912 10913 Input Parameters: 10914 + dm - The `DM` 10915 - dummy - unused argument 10916 10917 Options Database Key: 10918 . -dm_plex_monitor_throughput - Activate the monitor 10919 10920 Level: developer 10921 10922 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10923 @*/ 10924 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10925 { 10926 PetscLogHandler default_handler; 10927 10928 PetscFunctionBegin; 10929 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10930 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10931 if (default_handler) { 10932 PetscLogEvent event; 10933 PetscEventPerfInfo eventInfo; 10934 PetscLogDouble cellRate, flopRate; 10935 PetscInt cStart, cEnd, Nf, N; 10936 const char *name; 10937 10938 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10939 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10940 PetscCall(DMGetNumFields(dm, &Nf)); 10941 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10942 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10943 N = (cEnd - cStart) * Nf * eventInfo.count; 10944 flopRate = eventInfo.flops / eventInfo.time; 10945 cellRate = N / eventInfo.time; 10946 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)); 10947 } else { 10948 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."); 10949 } 10950 PetscFunctionReturn(PETSC_SUCCESS); 10951 } 10952