1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_CreateBoxSFC, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 /* Logging support */ 18 PetscLogEvent DMPLEX_DistributionView, DMPLEX_DistributionLoad; 19 20 PetscBool Plexcite = PETSC_FALSE; 21 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 22 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 23 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 24 "journal = {SIAM Journal on Scientific Computing},\n" 25 "volume = {38},\n" 26 "number = {5},\n" 27 "pages = {S143--S155},\n" 28 "eprint = {http://arxiv.org/abs/1506.07749},\n" 29 "doi = {10.1137/15M1026092},\n" 30 "year = {2016},\n" 31 "petsc_uses={DMPlex},\n}\n"; 32 33 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 34 35 /*@ 36 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 37 38 Input Parameter: 39 . dm - The `DMPLEX` object 40 41 Output Parameter: 42 . simplex - Flag checking for a simplex 43 44 Level: intermediate 45 46 Note: 47 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 48 If the mesh has no cells, this returns `PETSC_FALSE`. 49 50 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 51 @*/ 52 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 53 { 54 DMPolytopeType ct; 55 PetscInt cStart, cEnd; 56 57 PetscFunctionBegin; 58 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 59 if (cEnd <= cStart) { 60 *simplex = PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 64 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 65 PetscFunctionReturn(PETSC_SUCCESS); 66 } 67 68 /*@ 69 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 70 71 Input Parameters: 72 + dm - The `DMPLEX` object 73 - height - The cell height in the Plex, 0 is the default 74 75 Output Parameters: 76 + cStart - The first "normal" cell, pass `NULL` if not needed 77 - cEnd - The upper bound on "normal" cells, pass `NULL` if not needed 78 79 Level: developer 80 81 Note: 82 This function requires that tensor cells are ordered last. 83 84 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 85 @*/ 86 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PeOp PetscInt *cStart, PeOp PetscInt *cEnd) 87 { 88 DMLabel ctLabel; 89 IS valueIS; 90 const PetscInt *ctypes; 91 PetscBool found = PETSC_FALSE; 92 PetscInt Nct, cS = PETSC_INT_MAX, cE = 0; 93 94 PetscFunctionBegin; 95 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 96 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 97 PetscCall(ISGetLocalSize(valueIS, &Nct)); 98 PetscCall(ISGetIndices(valueIS, &ctypes)); 99 for (PetscInt t = 0; t < Nct; ++t) { 100 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 101 PetscInt ctS, ctE, ht; 102 103 if (ct == DM_POLYTOPE_UNKNOWN) { 104 // If any cells are not typed, just use all cells 105 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 106 break; 107 } 108 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 109 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 110 if (ctS >= ctE) continue; 111 // Check that a point has the right height 112 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 113 if (ht != height) continue; 114 cS = PetscMin(cS, ctS); 115 cE = PetscMax(cE, ctE); 116 found = PETSC_TRUE; 117 } 118 if (!Nct || !found) cS = cE = 0; 119 PetscCall(ISDestroy(&valueIS)); 120 // Reset label for fast lookup 121 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 122 if (cStart) *cStart = cS; 123 if (cEnd) *cEnd = cE; 124 PetscFunctionReturn(PETSC_SUCCESS); 125 } 126 127 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 128 { 129 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 130 PetscInt *sStart, *sEnd; 131 PetscViewerVTKFieldType *ft; 132 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 133 DMLabel depthLabel, ctLabel; 134 135 PetscFunctionBegin; 136 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 137 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 138 PetscCall(DMGetCoordinateDim(dm, &cdim)); 139 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 140 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 141 if (field >= 0) { 142 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 143 } else { 144 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 145 } 146 147 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 148 PetscCall(DMPlexGetDepth(dm, &depth)); 149 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 150 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 151 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 152 const DMPolytopeType ict = (DMPolytopeType)c; 153 PetscInt dep; 154 155 if (ict == DM_POLYTOPE_FV_GHOST) continue; 156 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 157 if (pStart >= 0) { 158 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 159 if (dep != depth - cellHeight) continue; 160 } 161 if (field >= 0) { 162 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 163 } else { 164 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 165 } 166 } 167 168 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 169 *types = 0; 170 171 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 172 if (globalvcdof[c]) ++(*types); 173 } 174 175 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 176 t = 0; 177 if (globalvcdof[DM_NUM_POLYTOPES]) { 178 sStart[t] = vStart; 179 sEnd[t] = vEnd; 180 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 181 ++t; 182 } 183 184 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 185 if (globalvcdof[c]) { 186 const DMPolytopeType ict = (DMPolytopeType)c; 187 188 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 189 sStart[t] = cStart; 190 sEnd[t] = cEnd; 191 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 192 ++t; 193 } 194 } 195 196 if (!*types) { 197 if (field >= 0) { 198 const char *fieldname; 199 200 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 201 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 202 } else { 203 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 204 } 205 } 206 207 *ssStart = sStart; 208 *ssEnd = sEnd; 209 *sft = ft; 210 PetscFunctionReturn(PETSC_SUCCESS); 211 } 212 213 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 214 { 215 PetscFunctionBegin; 216 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 217 PetscFunctionReturn(PETSC_SUCCESS); 218 } 219 220 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 221 { 222 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 223 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 224 225 PetscFunctionBegin; 226 *ft = PETSC_VTK_INVALID; 227 PetscCall(DMGetCoordinateDim(dm, &cdim)); 228 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 229 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 230 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 231 if (field >= 0) { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 234 } else { 235 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 236 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 237 } 238 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 239 if (globalvcdof[0]) { 240 *sStart = vStart; 241 *sEnd = vEnd; 242 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 243 else *ft = PETSC_VTK_POINT_FIELD; 244 } else if (globalvcdof[1]) { 245 *sStart = cStart; 246 *sEnd = cEnd; 247 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 248 else *ft = PETSC_VTK_CELL_FIELD; 249 } else { 250 if (field >= 0) { 251 const char *fieldname; 252 253 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 254 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 255 } else { 256 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n")); 257 } 258 } 259 PetscFunctionReturn(PETSC_SUCCESS); 260 } 261 262 /*@ 263 DMPlexVecView1D - Plot many 1D solutions on the same line graph 264 265 Collective 266 267 Input Parameters: 268 + dm - The `DMPLEX` object 269 . n - The number of vectors 270 . u - The array of local vectors 271 - viewer - The `PetscViewer` 272 273 Level: advanced 274 275 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 276 @*/ 277 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 278 { 279 DM cdm; 280 PetscDS ds; 281 PetscDraw draw = NULL; 282 PetscDrawLG lg; 283 Vec coordinates; 284 const PetscScalar *coords, **sol; 285 PetscReal *vals; 286 PetscInt *Nc; 287 PetscInt Nf, Nl, vStart, vEnd, eStart, eEnd; 288 char **names; 289 290 PetscFunctionBegin; 291 PetscCall(DMGetCoordinateDM(dm, &cdm)); 292 PetscCall(DMGetDS(dm, &ds)); 293 PetscCall(PetscDSGetNumFields(ds, &Nf)); 294 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 295 PetscCall(PetscDSGetComponents(ds, &Nc)); 296 297 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 298 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 299 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 300 301 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 302 for (PetscInt i = 0, l = 0; i < n; ++i) { 303 const char *vname; 304 305 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 306 for (PetscInt f = 0; f < Nf; ++f) { 307 PetscObject disc; 308 const char *fname; 309 char tmpname[PETSC_MAX_PATH_LEN]; 310 311 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 312 /* TODO Create names for components */ 313 for (PetscInt c = 0; c < Nc[f]; ++c, ++l) { 314 PetscCall(PetscObjectGetName(disc, &fname)); 315 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 316 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 317 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 318 PetscCall(PetscStrallocpy(tmpname, &names[l])); 319 } 320 } 321 } 322 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 323 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 324 PetscCall(VecGetArrayRead(coordinates, &coords)); 325 for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 326 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 327 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 328 PetscSection s; 329 PetscInt cdof, vdof; 330 331 PetscCall(DMGetLocalSection(dm, &s)); 332 PetscCall(PetscSectionGetDof(s, eStart, &cdof)); 333 PetscCall(PetscSectionGetDof(s, vStart, &vdof)); 334 if (cdof) { 335 if (vdof) { 336 // P_2 337 PetscInt vFirst = -1; 338 339 for (PetscInt e = eStart; e < eEnd; ++e) { 340 PetscScalar *xa, *xb, *svals; 341 const PetscInt *cone; 342 343 PetscCall(DMPlexGetCone(dm, e, &cone)); 344 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 345 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 346 if (e == eStart) vFirst = cone[0]; 347 for (PetscInt i = 0; i < n; ++i) { 348 PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals)); 349 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 350 } 351 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals)); 352 if (e == eEnd - 1 && cone[1] != vFirst) { 353 for (PetscInt i = 0; i < n; ++i) { 354 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 355 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 356 } 357 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 358 for (PetscInt i = 0; i < n; ++i) { 359 PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals)); 360 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 361 } 362 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals)); 363 } 364 } 365 } else { 366 // P_0 367 for (PetscInt e = eStart; e < eEnd; ++e) { 368 PetscScalar *xa, *xb, *svals; 369 const PetscInt *cone; 370 371 PetscCall(DMPlexGetCone(dm, e, &cone)); 372 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 373 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 374 for (PetscInt i = 0; i < n; ++i) { 375 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 376 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 377 } 378 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 379 } 380 } 381 } else if (vdof) { 382 // P_1 383 for (PetscInt v = vStart; v < vEnd; ++v) { 384 PetscScalar *x, *svals; 385 386 PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x)); 387 for (PetscInt i = 0; i < n; ++i) { 388 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 389 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 390 } 391 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 392 } 393 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Discretization not supported"); 394 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 395 for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 396 for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 397 PetscCall(PetscFree3(sol, names, vals)); 398 399 PetscCall(PetscDrawLGDraw(lg)); 400 PetscCall(PetscDrawLGDestroy(&lg)); 401 PetscFunctionReturn(PETSC_SUCCESS); 402 } 403 404 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 405 { 406 DM dm; 407 408 PetscFunctionBegin; 409 PetscCall(VecGetDM(u, &dm)); 410 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 411 PetscFunctionReturn(PETSC_SUCCESS); 412 } 413 414 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 415 { 416 DM dm; 417 PetscSection s; 418 PetscDraw draw, popup; 419 DM cdm; 420 PetscSection coordSection; 421 Vec coordinates; 422 const PetscScalar *array; 423 PetscReal lbound[3], ubound[3]; 424 PetscReal vbound[2], time; 425 PetscBool flg; 426 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 427 const char *name; 428 char title[PETSC_MAX_PATH_LEN]; 429 430 PetscFunctionBegin; 431 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 432 PetscCall(VecGetDM(v, &dm)); 433 PetscCall(DMGetCoordinateDim(dm, &dim)); 434 PetscCall(DMGetLocalSection(dm, &s)); 435 PetscCall(PetscSectionGetNumFields(s, &Nf)); 436 PetscCall(DMGetCoarsenLevel(dm, &level)); 437 PetscCall(DMGetCoordinateDM(dm, &cdm)); 438 PetscCall(DMGetLocalSection(cdm, &coordSection)); 439 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 440 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 441 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 442 443 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 444 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 445 446 PetscCall(VecGetLocalSize(coordinates, &N)); 447 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 448 PetscCall(PetscDrawClear(draw)); 449 450 /* Could implement something like DMDASelectFields() */ 451 for (f = 0; f < Nf; ++f) { 452 DM fdm = dm; 453 Vec fv = v; 454 IS fis; 455 char prefix[PETSC_MAX_PATH_LEN]; 456 const char *fname; 457 458 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 459 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 460 461 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 462 else prefix[0] = '\0'; 463 if (Nf > 1) { 464 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 465 PetscCall(VecGetSubVector(v, fis, &fv)); 466 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 467 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 468 } 469 for (comp = 0; comp < Nc; ++comp, ++w) { 470 PetscInt nmax = 2; 471 472 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 473 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 474 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 475 PetscCall(PetscDrawSetTitle(draw, title)); 476 477 /* TODO Get max and min only for this component */ 478 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 479 if (!flg) { 480 PetscCall(VecMin(fv, NULL, &vbound[0])); 481 PetscCall(VecMax(fv, NULL, &vbound[1])); 482 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 483 } 484 485 PetscCall(PetscDrawGetPopup(draw, &popup)); 486 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 487 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 488 PetscCall(VecGetArrayRead(fv, &array)); 489 for (c = cStart; c < cEnd; ++c) { 490 DMPolytopeType ct; 491 PetscScalar *coords = NULL, *a = NULL; 492 const PetscScalar *coords_arr; 493 PetscBool isDG; 494 PetscInt numCoords; 495 int color[4] = {-1, -1, -1, -1}; 496 497 PetscCall(DMPlexGetCellType(dm, c, &ct)); 498 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 499 if (a) { 500 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 501 color[1] = color[2] = color[3] = color[0]; 502 } else { 503 PetscScalar *vals = NULL; 504 PetscInt numVals, va; 505 506 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 507 if (!numVals) { 508 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 509 continue; 510 } 511 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 512 switch (numVals / Nc) { 513 case 1: /* P1 Clamped Segment Prism */ 514 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 515 PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]); 516 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 517 break; 518 case 3: /* P1 Triangle */ 519 case 4: /* P1 Quadrangle */ 520 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 521 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 522 break; 523 case 6: /* P2 Triangle */ 524 case 8: /* P2 Quadrangle */ 525 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 526 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 527 break; 528 default: 529 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 530 } 531 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 532 } 533 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 534 switch (numCoords) { 535 case 6: 536 case 12: /* Localized triangle */ 537 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 538 break; 539 case 8: 540 case 16: /* Localized quadrilateral */ 541 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 542 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 543 } else { 544 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 545 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 546 } 547 break; 548 default: 549 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 550 } 551 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 552 } 553 PetscCall(VecRestoreArrayRead(fv, &array)); 554 PetscCall(PetscDrawFlush(draw)); 555 PetscCall(PetscDrawPause(draw)); 556 PetscCall(PetscDrawSave(draw)); 557 } 558 if (Nf > 1) { 559 PetscCall(VecRestoreSubVector(v, fis, &fv)); 560 PetscCall(ISDestroy(&fis)); 561 PetscCall(DMDestroy(&fdm)); 562 } 563 } 564 PetscFunctionReturn(PETSC_SUCCESS); 565 } 566 567 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 568 { 569 DM dm; 570 PetscDraw draw; 571 PetscInt dim; 572 PetscBool isnull; 573 574 PetscFunctionBegin; 575 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 576 PetscCall(PetscDrawIsNull(draw, &isnull)); 577 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 578 579 PetscCall(VecGetDM(v, &dm)); 580 PetscCall(DMGetCoordinateDim(dm, &dim)); 581 switch (dim) { 582 case 1: 583 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 584 break; 585 case 2: 586 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 587 break; 588 default: 589 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 590 } 591 PetscFunctionReturn(PETSC_SUCCESS); 592 } 593 594 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 595 { 596 DM dm; 597 Vec locv; 598 const char *name; 599 PetscSection section; 600 PetscInt pStart, pEnd; 601 PetscInt numFields; 602 PetscViewerVTKFieldType ft; 603 604 PetscFunctionBegin; 605 PetscCall(VecGetDM(v, &dm)); 606 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 607 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 608 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 609 PetscCall(VecCopy(v, locv)); 610 PetscCall(DMGetLocalSection(dm, §ion)); 611 PetscCall(PetscSectionGetNumFields(section, &numFields)); 612 if (!numFields) { 613 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 614 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 615 } else { 616 PetscInt f; 617 618 for (f = 0; f < numFields; f++) { 619 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 620 if (ft == PETSC_VTK_INVALID) continue; 621 PetscCall(PetscObjectReference((PetscObject)locv)); 622 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 623 } 624 PetscCall(VecDestroy(&locv)); 625 } 626 PetscFunctionReturn(PETSC_SUCCESS); 627 } 628 629 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 630 { 631 DM dm; 632 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython; 633 634 PetscFunctionBegin; 635 PetscCall(VecGetDM(v, &dm)); 636 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 640 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 641 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 642 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 643 if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) { 644 PetscInt i, numFields; 645 PetscObject fe; 646 PetscBool fem = PETSC_FALSE; 647 Vec locv = v; 648 const char *name; 649 PetscInt step; 650 PetscReal time; 651 652 PetscCall(DMGetNumFields(dm, &numFields)); 653 for (i = 0; i < numFields; i++) { 654 PetscCall(DMGetField(dm, i, NULL, &fe)); 655 if (fe->classid == PETSCFE_CLASSID) { 656 fem = PETSC_TRUE; 657 break; 658 } 659 } 660 if (fem) { 661 PetscObject isZero; 662 663 PetscCall(DMGetLocalVector(dm, &locv)); 664 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 665 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 666 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 667 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 668 PetscCall(VecCopy(v, locv)); 669 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 670 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 671 } 672 if (isvtk) { 673 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 674 } else if (ishdf5) { 675 #if defined(PETSC_HAVE_HDF5) 676 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 677 #else 678 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 679 #endif 680 } else if (isdraw) { 681 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 682 } else if (ispython) { 683 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv)); 684 } else if (isglvis) { 685 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 686 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 687 PetscCall(VecView_GLVis(locv, viewer)); 688 } else if (iscgns) { 689 #if defined(PETSC_HAVE_CGNS) 690 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 691 #else 692 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 693 #endif 694 } 695 if (fem) { 696 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 697 PetscCall(DMRestoreLocalVector(dm, &locv)); 698 } 699 } else { 700 PetscBool isseq; 701 702 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 703 if (isseq) PetscCall(VecView_Seq(v, viewer)); 704 else PetscCall(VecView_MPI(v, viewer)); 705 } 706 PetscFunctionReturn(PETSC_SUCCESS); 707 } 708 709 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 710 { 711 DM dm; 712 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython; 713 714 PetscFunctionBegin; 715 PetscCall(VecGetDM(v, &dm)); 716 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 721 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 722 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 723 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 724 if (isvtk || isdraw || isglvis || iscgns || ispython) { 725 Vec locv; 726 PetscObject isZero; 727 const char *name; 728 729 PetscCall(DMGetLocalVector(dm, &locv)); 730 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 731 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 732 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 733 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 734 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 735 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 736 PetscCall(VecView_Plex_Local(locv, viewer)); 737 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 738 PetscCall(DMRestoreLocalVector(dm, &locv)); 739 } else if (ishdf5) { 740 #if defined(PETSC_HAVE_HDF5) 741 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 742 #else 743 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 744 #endif 745 } else if (isexodusii) { 746 #if defined(PETSC_HAVE_EXODUSII) 747 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 748 #else 749 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 750 #endif 751 } else { 752 PetscBool isseq; 753 754 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 755 if (isseq) PetscCall(VecView_Seq(v, viewer)); 756 else PetscCall(VecView_MPI(v, viewer)); 757 } 758 PetscFunctionReturn(PETSC_SUCCESS); 759 } 760 761 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 762 { 763 DM dm; 764 MPI_Comm comm; 765 PetscViewerFormat format; 766 Vec v; 767 PetscBool isvtk, ishdf5; 768 769 PetscFunctionBegin; 770 PetscCall(VecGetDM(originalv, &dm)); 771 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 772 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 773 PetscCall(PetscViewerGetFormat(viewer, &format)); 774 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 775 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 776 if (format == PETSC_VIEWER_NATIVE) { 777 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 778 /* this need a better fix */ 779 if (dm->useNatural) { 780 if (dm->sfNatural) { 781 const char *vecname; 782 PetscInt n, nroots; 783 784 PetscCall(VecGetLocalSize(originalv, &n)); 785 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 786 if (n == nroots) { 787 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 788 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 789 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 790 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 791 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 792 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 793 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 794 } else v = originalv; 795 } else v = originalv; 796 797 if (ishdf5) { 798 #if defined(PETSC_HAVE_HDF5) 799 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 800 #else 801 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 802 #endif 803 } else if (isvtk) { 804 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 805 } else { 806 PetscBool isseq; 807 808 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 809 if (isseq) PetscCall(VecView_Seq(v, viewer)); 810 else PetscCall(VecView_MPI(v, viewer)); 811 } 812 if (v != originalv) PetscCall(VecDestroy(&v)); 813 PetscFunctionReturn(PETSC_SUCCESS); 814 } 815 816 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 817 { 818 DM dm; 819 PetscBool ishdf5; 820 821 PetscFunctionBegin; 822 PetscCall(VecGetDM(v, &dm)); 823 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 824 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 825 if (ishdf5) { 826 DM dmBC; 827 Vec gv; 828 const char *name; 829 830 PetscCall(DMGetOutputDM(dm, &dmBC)); 831 PetscCall(DMGetGlobalVector(dmBC, &gv)); 832 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 833 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 834 PetscCall(VecLoad_Default(gv, viewer)); 835 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 836 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 837 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 838 } else PetscCall(VecLoad_Default(v, viewer)); 839 PetscFunctionReturn(PETSC_SUCCESS); 840 } 841 842 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 843 { 844 DM dm; 845 PetscBool ishdf5, isexodusii, iscgns; 846 847 PetscFunctionBegin; 848 PetscCall(VecGetDM(v, &dm)); 849 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 850 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 851 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 852 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 853 if (ishdf5) { 854 #if defined(PETSC_HAVE_HDF5) 855 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 856 #else 857 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 858 #endif 859 } else if (isexodusii) { 860 #if defined(PETSC_HAVE_EXODUSII) 861 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 862 #else 863 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 864 #endif 865 } else if (iscgns) { 866 #if defined(PETSC_HAVE_CGNS) 867 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 868 #else 869 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 870 #endif 871 } else PetscCall(VecLoad_Default(v, viewer)); 872 PetscFunctionReturn(PETSC_SUCCESS); 873 } 874 875 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 876 { 877 DM dm; 878 PetscViewerFormat format; 879 PetscBool ishdf5; 880 881 PetscFunctionBegin; 882 PetscCall(VecGetDM(originalv, &dm)); 883 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 884 PetscCall(PetscViewerGetFormat(viewer, &format)); 885 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 886 if (format == PETSC_VIEWER_NATIVE) { 887 if (dm->useNatural) { 888 if (dm->sfNatural) { 889 if (ishdf5) { 890 #if defined(PETSC_HAVE_HDF5) 891 Vec v; 892 const char *vecname; 893 894 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 895 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 896 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 897 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 898 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 899 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 900 PetscCall(VecDestroy(&v)); 901 #else 902 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 903 #endif 904 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 905 } 906 } else PetscCall(VecLoad_Default(originalv, viewer)); 907 } 908 PetscFunctionReturn(PETSC_SUCCESS); 909 } 910 911 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 912 { 913 PetscSection coordSection; 914 Vec coordinates; 915 DMLabel depthLabel, celltypeLabel; 916 const char *name[4]; 917 const PetscScalar *a; 918 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 919 920 PetscFunctionBegin; 921 PetscCall(DMGetDimension(dm, &dim)); 922 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 923 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 924 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 925 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 926 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 927 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 928 PetscCall(VecGetArrayRead(coordinates, &a)); 929 name[0] = "vertex"; 930 name[1] = "edge"; 931 name[dim - 1] = "face"; 932 name[dim] = "cell"; 933 for (c = cStart; c < cEnd; ++c) { 934 PetscInt *closure = NULL; 935 PetscInt closureSize, cl, ct; 936 937 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 938 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 939 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 940 PetscCall(PetscViewerASCIIPushTab(viewer)); 941 for (cl = 0; cl < closureSize * 2; cl += 2) { 942 PetscInt point = closure[cl], depth, dof, off, d, p; 943 944 if ((point < pStart) || (point >= pEnd)) continue; 945 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 946 if (!dof) continue; 947 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 948 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 949 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 950 for (p = 0; p < dof / dim; ++p) { 951 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 952 for (d = 0; d < dim; ++d) { 953 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 955 } 956 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 957 } 958 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 959 } 960 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 961 PetscCall(PetscViewerASCIIPopTab(viewer)); 962 } 963 PetscCall(VecRestoreArrayRead(coordinates, &a)); 964 PetscFunctionReturn(PETSC_SUCCESS); 965 } 966 967 typedef enum { 968 CS_CARTESIAN, 969 CS_POLAR, 970 CS_CYLINDRICAL, 971 CS_SPHERICAL 972 } CoordSystem; 973 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 974 975 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 976 { 977 PetscInt i; 978 979 PetscFunctionBegin; 980 if (dim > 3) { 981 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 982 } else { 983 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 984 985 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 986 switch (cs) { 987 case CS_CARTESIAN: 988 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 989 break; 990 case CS_POLAR: 991 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 992 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 993 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 994 break; 995 case CS_CYLINDRICAL: 996 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 997 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 998 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 999 trcoords[2] = coords[2]; 1000 break; 1001 case CS_SPHERICAL: 1002 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 1003 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 1004 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 1005 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 1006 break; 1007 } 1008 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 1009 } 1010 PetscFunctionReturn(PETSC_SUCCESS); 1011 } 1012 1013 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 1014 { 1015 DM_Plex *mesh = (DM_Plex *)dm->data; 1016 DM cdm, cdmCell; 1017 PetscSection coordSection, coordSectionCell; 1018 Vec coordinates, coordinatesCell; 1019 PetscViewerFormat format; 1020 1021 PetscFunctionBegin; 1022 PetscCall(PetscViewerGetFormat(viewer, &format)); 1023 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1024 const char *name; 1025 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1026 PetscInt pStart, pEnd, p, numLabels, l; 1027 PetscMPIInt rank, size; 1028 1029 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1030 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1031 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1032 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1033 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1034 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1035 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1036 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1037 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1038 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1039 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1040 PetscCall(DMGetDimension(dm, &dim)); 1041 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1042 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1043 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1044 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1045 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1046 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1047 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1048 for (p = pStart; p < pEnd; ++p) { 1049 PetscInt dof, off, s; 1050 1051 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1052 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1053 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1054 } 1055 PetscCall(PetscViewerFlush(viewer)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1057 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1058 for (p = pStart; p < pEnd; ++p) { 1059 PetscInt dof, off, c; 1060 1061 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1062 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1063 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 1064 } 1065 PetscCall(PetscViewerFlush(viewer)); 1066 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1067 if (coordSection && coordinates) { 1068 CoordSystem cs = CS_CARTESIAN; 1069 const PetscScalar *array, *arrayCell = NULL; 1070 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1071 PetscMPIInt rank; 1072 const char *name; 1073 1074 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1075 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1076 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1077 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1078 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1079 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1080 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1081 pStart = PetscMin(pvStart, pcStart); 1082 pEnd = PetscMax(pvEnd, pcEnd); 1083 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1084 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1085 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1086 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1087 1088 PetscCall(VecGetArrayRead(coordinates, &array)); 1089 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1090 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1091 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1092 for (p = pStart; p < pEnd; ++p) { 1093 PetscInt dof, off; 1094 1095 if (p >= pvStart && p < pvEnd) { 1096 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1097 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1098 if (dof) { 1099 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1100 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1101 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1102 } 1103 } 1104 if (cdmCell && p >= pcStart && p < pcEnd) { 1105 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1106 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1107 if (dof) { 1108 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1109 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1110 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1111 } 1112 } 1113 } 1114 PetscCall(PetscViewerFlush(viewer)); 1115 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1116 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1117 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1118 } 1119 PetscCall(DMGetNumLabels(dm, &numLabels)); 1120 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1121 for (l = 0; l < numLabels; ++l) { 1122 DMLabel label; 1123 PetscBool isdepth; 1124 const char *name; 1125 1126 PetscCall(DMGetLabelName(dm, l, &name)); 1127 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1128 if (isdepth) continue; 1129 PetscCall(DMGetLabel(dm, name, &label)); 1130 PetscCall(DMLabelView(label, viewer)); 1131 } 1132 if (size > 1) { 1133 PetscSF sf; 1134 1135 PetscCall(DMGetPointSF(dm, &sf)); 1136 PetscCall(PetscSFView(sf, viewer)); 1137 } 1138 if (mesh->periodic.face_sfs) 1139 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1140 PetscCall(PetscViewerFlush(viewer)); 1141 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1142 const char *name, *color; 1143 const char *defcolors[3] = {"gray", "orange", "green"}; 1144 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1145 char lname[PETSC_MAX_PATH_LEN]; 1146 PetscReal scale = 2.0; 1147 PetscReal tikzscale = 1.0; 1148 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1149 double tcoords[3]; 1150 PetscScalar *coords; 1151 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 1152 PetscMPIInt rank, size; 1153 char **names, **colors, **lcolors; 1154 PetscBool flg, lflg; 1155 PetscBT wp = NULL; 1156 PetscInt pEnd, pStart; 1157 1158 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1159 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1160 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1161 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1162 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1163 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1164 PetscCall(DMGetDimension(dm, &dim)); 1165 PetscCall(DMPlexGetDepth(dm, &depth)); 1166 PetscCall(DMGetNumLabels(dm, &numLabels)); 1167 numLabels = PetscMax(numLabels, 10); 1168 numColors = 10; 1169 numLColors = 10; 1170 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1171 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1172 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1173 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1174 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1175 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1176 n = 4; 1177 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1178 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1179 n = 4; 1180 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1181 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1182 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1183 if (!useLabels) numLabels = 0; 1184 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1185 if (!useColors) { 1186 numColors = 3; 1187 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1188 } 1189 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1190 if (!useColors) { 1191 numLColors = 4; 1192 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1193 } 1194 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1195 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1196 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1197 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1198 if (depth < dim) plotEdges = PETSC_FALSE; 1199 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1200 1201 /* filter points with labelvalue != labeldefaultvalue */ 1202 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1203 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1204 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1205 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1206 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1207 if (lflg) { 1208 DMLabel lbl; 1209 1210 PetscCall(DMGetLabel(dm, lname, &lbl)); 1211 if (lbl) { 1212 PetscInt val, defval; 1213 1214 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1215 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1216 for (c = pStart; c < pEnd; c++) { 1217 PetscInt *closure = NULL; 1218 PetscInt closureSize; 1219 1220 PetscCall(DMLabelGetValue(lbl, c, &val)); 1221 if (val == defval) continue; 1222 1223 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1224 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1225 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1226 } 1227 } 1228 } 1229 1230 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1231 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1232 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1234 \\documentclass[tikz]{standalone}\n\n\ 1235 \\usepackage{pgflibraryshapes}\n\ 1236 \\usetikzlibrary{backgrounds}\n\ 1237 \\usetikzlibrary{arrows}\n\ 1238 \\begin{document}\n")); 1239 if (size > 1) { 1240 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1241 for (p = 0; p < size; ++p) { 1242 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1243 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1244 } 1245 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1246 } 1247 if (drawHasse) { 1248 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1249 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1258 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1264 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1265 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1266 } 1267 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1268 1269 /* Plot vertices */ 1270 PetscCall(VecGetArray(coordinates, &coords)); 1271 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1272 for (v = vStart; v < vEnd; ++v) { 1273 PetscInt off, dof, d; 1274 PetscBool isLabeled = PETSC_FALSE; 1275 1276 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1277 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1278 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1280 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1281 for (d = 0; d < dof; ++d) { 1282 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1283 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1284 } 1285 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1286 if (dim == 3) { 1287 PetscReal tmp = tcoords[1]; 1288 tcoords[1] = tcoords[2]; 1289 tcoords[2] = -tmp; 1290 } 1291 for (d = 0; d < dof; ++d) { 1292 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1293 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1294 } 1295 if (drawHasse) color = colors[0 % numColors]; 1296 else color = colors[rank % numColors]; 1297 for (l = 0; l < numLabels; ++l) { 1298 PetscInt val; 1299 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1300 if (val >= 0) { 1301 color = lcolors[l % numLColors]; 1302 isLabeled = PETSC_TRUE; 1303 break; 1304 } 1305 } 1306 if (drawNumbers[0]) { 1307 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1308 } else if (drawColors[0]) { 1309 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1310 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1311 } 1312 PetscCall(VecRestoreArray(coordinates, &coords)); 1313 PetscCall(PetscViewerFlush(viewer)); 1314 /* Plot edges */ 1315 if (plotEdges) { 1316 PetscCall(VecGetArray(coordinates, &coords)); 1317 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1318 for (e = eStart; e < eEnd; ++e) { 1319 const PetscInt *cone; 1320 PetscInt coneSize, offA, offB, dof, d; 1321 1322 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1323 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1324 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1325 PetscCall(DMPlexGetCone(dm, e, &cone)); 1326 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1327 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1328 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1329 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1330 for (d = 0; d < dof; ++d) { 1331 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1332 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1333 } 1334 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1335 if (dim == 3) { 1336 PetscReal tmp = tcoords[1]; 1337 tcoords[1] = tcoords[2]; 1338 tcoords[2] = -tmp; 1339 } 1340 for (d = 0; d < dof; ++d) { 1341 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1342 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1343 } 1344 if (drawHasse) color = colors[1 % numColors]; 1345 else color = colors[rank % numColors]; 1346 for (l = 0; l < numLabels; ++l) { 1347 PetscInt val; 1348 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1349 if (val >= 0) { 1350 color = lcolors[l % numLColors]; 1351 break; 1352 } 1353 } 1354 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1355 } 1356 PetscCall(VecRestoreArray(coordinates, &coords)); 1357 PetscCall(PetscViewerFlush(viewer)); 1358 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1359 } 1360 /* Plot cells */ 1361 if (dim == 3 || !drawNumbers[1]) { 1362 for (e = eStart; e < eEnd; ++e) { 1363 const PetscInt *cone; 1364 1365 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1366 color = colors[rank % numColors]; 1367 for (l = 0; l < numLabels; ++l) { 1368 PetscInt val; 1369 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1370 if (val >= 0) { 1371 color = lcolors[l % numLColors]; 1372 break; 1373 } 1374 } 1375 PetscCall(DMPlexGetCone(dm, e, &cone)); 1376 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1377 } 1378 } else { 1379 DMPolytopeType ct; 1380 1381 /* Drawing a 2D polygon */ 1382 for (c = cStart; c < cEnd; ++c) { 1383 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1384 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1385 if (DMPolytopeTypeIsHybrid(ct)) { 1386 const PetscInt *cone; 1387 PetscInt coneSize, e; 1388 1389 PetscCall(DMPlexGetCone(dm, c, &cone)); 1390 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1391 for (e = 0; e < coneSize; ++e) { 1392 const PetscInt *econe; 1393 1394 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1395 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1396 } 1397 } else { 1398 PetscInt *closure = NULL; 1399 PetscInt closureSize, Nv = 0, v; 1400 1401 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1402 for (p = 0; p < closureSize * 2; p += 2) { 1403 const PetscInt point = closure[p]; 1404 1405 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1406 } 1407 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1408 for (v = 0; v <= Nv; ++v) { 1409 const PetscInt vertex = closure[v % Nv]; 1410 1411 if (v > 0) { 1412 if (plotEdges) { 1413 const PetscInt *edge; 1414 PetscInt endpoints[2], ne; 1415 1416 endpoints[0] = closure[v - 1]; 1417 endpoints[1] = vertex; 1418 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1419 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1420 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1421 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1422 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1423 } 1424 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1425 } 1426 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1427 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1428 } 1429 } 1430 } 1431 for (c = cStart; c < cEnd; ++c) { 1432 double ccoords[3] = {0.0, 0.0, 0.0}; 1433 PetscBool isLabeled = PETSC_FALSE; 1434 PetscScalar *cellCoords = NULL; 1435 const PetscScalar *array; 1436 PetscInt numCoords, cdim, d; 1437 PetscBool isDG; 1438 1439 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1440 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1441 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1442 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1443 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1444 for (p = 0; p < numCoords / cdim; ++p) { 1445 for (d = 0; d < cdim; ++d) { 1446 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1447 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1448 } 1449 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1450 if (cdim == 3) { 1451 PetscReal tmp = tcoords[1]; 1452 tcoords[1] = tcoords[2]; 1453 tcoords[2] = -tmp; 1454 } 1455 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1456 } 1457 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1458 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1459 for (d = 0; d < cdim; ++d) { 1460 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1461 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1462 } 1463 if (drawHasse) color = colors[depth % numColors]; 1464 else color = colors[rank % numColors]; 1465 for (l = 0; l < numLabels; ++l) { 1466 PetscInt val; 1467 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1468 if (val >= 0) { 1469 color = lcolors[l % numLColors]; 1470 isLabeled = PETSC_TRUE; 1471 break; 1472 } 1473 } 1474 if (drawNumbers[dim]) { 1475 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1476 } else if (drawColors[dim]) { 1477 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1478 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1479 } 1480 if (drawHasse) { 1481 int height = 0; 1482 1483 color = colors[depth % numColors]; 1484 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1485 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1486 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1487 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1489 1490 if (depth > 2) { 1491 color = colors[1 % numColors]; 1492 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1493 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1494 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1495 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1496 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1497 } 1498 1499 color = colors[1 % numColors]; 1500 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1502 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1503 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1504 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1505 1506 color = colors[0 % numColors]; 1507 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1510 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1511 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1512 1513 for (p = pStart; p < pEnd; ++p) { 1514 const PetscInt *cone; 1515 PetscInt coneSize, cp; 1516 1517 PetscCall(DMPlexGetCone(dm, p, &cone)); 1518 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1519 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1520 } 1521 } 1522 PetscCall(PetscViewerFlush(viewer)); 1523 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1524 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1525 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1526 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1527 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1528 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1529 PetscCall(PetscFree3(names, colors, lcolors)); 1530 PetscCall(PetscBTDestroy(&wp)); 1531 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1532 Vec cown, acown; 1533 VecScatter sct; 1534 ISLocalToGlobalMapping g2l; 1535 IS gid, acis; 1536 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1537 MPI_Group ggroup, ngroup; 1538 PetscScalar *array, nid; 1539 const PetscInt *idxs; 1540 PetscInt *idxs2, *start, *adjacency, *work; 1541 PetscInt64 lm[3], gm[3]; 1542 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1543 PetscMPIInt d1, d2, rank; 1544 1545 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1546 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1547 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1548 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1549 #endif 1550 if (ncomm != MPI_COMM_NULL) { 1551 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1552 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1553 d1 = 0; 1554 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1555 nid = d2; 1556 PetscCallMPI(MPI_Group_free(&ggroup)); 1557 PetscCallMPI(MPI_Group_free(&ngroup)); 1558 PetscCallMPI(MPI_Comm_free(&ncomm)); 1559 } else nid = 0.0; 1560 1561 /* Get connectivity */ 1562 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1563 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1564 1565 /* filter overlapped local cells */ 1566 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1567 PetscCall(ISGetIndices(gid, &idxs)); 1568 PetscCall(ISGetLocalSize(gid, &cum)); 1569 PetscCall(PetscMalloc1(cum, &idxs2)); 1570 for (c = cStart, cum = 0; c < cEnd; c++) { 1571 if (idxs[c - cStart] < 0) continue; 1572 idxs2[cum++] = idxs[c - cStart]; 1573 } 1574 PetscCall(ISRestoreIndices(gid, &idxs)); 1575 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1576 PetscCall(ISDestroy(&gid)); 1577 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1578 1579 /* support for node-aware cell locality */ 1580 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1581 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1582 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1583 PetscCall(VecGetArray(cown, &array)); 1584 for (c = 0; c < numVertices; c++) array[c] = nid; 1585 PetscCall(VecRestoreArray(cown, &array)); 1586 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1587 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1588 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1589 PetscCall(ISDestroy(&acis)); 1590 PetscCall(VecScatterDestroy(&sct)); 1591 PetscCall(VecDestroy(&cown)); 1592 1593 /* compute edgeCut */ 1594 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1595 PetscCall(PetscMalloc1(cum, &work)); 1596 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1597 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1598 PetscCall(ISDestroy(&gid)); 1599 PetscCall(VecGetArray(acown, &array)); 1600 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1601 PetscInt totl; 1602 1603 totl = start[c + 1] - start[c]; 1604 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1605 for (i = 0; i < totl; i++) { 1606 if (work[i] < 0) { 1607 ect += 1; 1608 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1609 } 1610 } 1611 } 1612 PetscCall(PetscFree(work)); 1613 PetscCall(VecRestoreArray(acown, &array)); 1614 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1615 lm[1] = -numVertices; 1616 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1617 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1618 lm[0] = ect; /* edgeCut */ 1619 lm[1] = ectn; /* node-aware edgeCut */ 1620 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1621 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1622 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1623 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1624 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1625 #else 1626 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1627 #endif 1628 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1629 PetscCall(PetscFree(start)); 1630 PetscCall(PetscFree(adjacency)); 1631 PetscCall(VecDestroy(&acown)); 1632 } else { 1633 const char *name; 1634 PetscInt *sizes, *hybsizes, *ghostsizes; 1635 PetscInt locDepth, depth, cellHeight, dim, d; 1636 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1637 PetscInt numLabels, l, maxSize = 17; 1638 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1639 MPI_Comm comm; 1640 PetscMPIInt size, rank; 1641 1642 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1643 PetscCallMPI(MPI_Comm_size(comm, &size)); 1644 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1645 PetscCall(DMGetDimension(dm, &dim)); 1646 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1647 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1648 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1649 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1650 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1651 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1652 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1653 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1654 gcNum = gcEnd - gcStart; 1655 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1656 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1657 for (d = 0; d <= depth; d++) { 1658 PetscInt Nc[2] = {0, 0}, ict; 1659 1660 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1661 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1662 ict = ct0; 1663 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1664 ct0 = (DMPolytopeType)ict; 1665 for (p = pStart; p < pEnd; ++p) { 1666 DMPolytopeType ct; 1667 1668 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1669 if (ct == ct0) ++Nc[0]; 1670 else ++Nc[1]; 1671 } 1672 if (size < maxSize) { 1673 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1674 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1675 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1676 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1677 for (p = 0; p < size; ++p) { 1678 if (rank == 0) { 1679 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1680 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1681 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1682 } 1683 } 1684 } else { 1685 PetscInt locMinMax[2]; 1686 1687 locMinMax[0] = Nc[0] + Nc[1]; 1688 locMinMax[1] = Nc[0] + Nc[1]; 1689 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1690 locMinMax[0] = Nc[1]; 1691 locMinMax[1] = Nc[1]; 1692 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1693 if (d == depth) { 1694 locMinMax[0] = gcNum; 1695 locMinMax[1] = gcNum; 1696 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1697 } 1698 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1699 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1700 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1701 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1702 } 1703 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1704 } 1705 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1706 { 1707 const PetscReal *maxCell; 1708 const PetscReal *L; 1709 PetscBool localized; 1710 1711 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1712 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1713 if (L || localized) { 1714 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1715 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1716 if (L) { 1717 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1718 for (d = 0; d < dim; ++d) { 1719 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1720 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1721 } 1722 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1723 } 1724 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1725 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1726 } 1727 } 1728 PetscCall(DMGetNumLabels(dm, &numLabels)); 1729 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1730 for (l = 0; l < numLabels; ++l) { 1731 DMLabel label; 1732 const char *name; 1733 PetscInt *values; 1734 PetscInt numValues, v; 1735 1736 PetscCall(DMGetLabelName(dm, l, &name)); 1737 PetscCall(DMGetLabel(dm, name, &label)); 1738 PetscCall(DMLabelGetNumValues(label, &numValues)); 1739 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1740 1741 { // Extract array of DMLabel values so it can be sorted 1742 IS is_values; 1743 const PetscInt *is_values_local = NULL; 1744 1745 PetscCall(DMLabelGetValueIS(label, &is_values)); 1746 PetscCall(ISGetIndices(is_values, &is_values_local)); 1747 PetscCall(PetscMalloc1(numValues, &values)); 1748 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1749 PetscCall(PetscSortInt(numValues, values)); 1750 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1751 PetscCall(ISDestroy(&is_values)); 1752 } 1753 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1754 for (v = 0; v < numValues; ++v) { 1755 PetscInt size; 1756 1757 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1758 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1759 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1760 } 1761 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1762 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1763 PetscCall(PetscFree(values)); 1764 } 1765 { 1766 char **labelNames; 1767 PetscInt Nl = numLabels; 1768 PetscBool flg; 1769 1770 PetscCall(PetscMalloc1(Nl, &labelNames)); 1771 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1772 for (l = 0; l < Nl; ++l) { 1773 DMLabel label; 1774 1775 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1776 if (flg) { 1777 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1778 PetscCall(DMLabelView(label, viewer)); 1779 } 1780 PetscCall(PetscFree(labelNames[l])); 1781 } 1782 PetscCall(PetscFree(labelNames)); 1783 } 1784 /* If no fields are specified, people do not want to see adjacency */ 1785 if (dm->Nf) { 1786 PetscInt f; 1787 1788 for (f = 0; f < dm->Nf; ++f) { 1789 const char *name; 1790 1791 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1792 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1793 PetscCall(PetscViewerASCIIPushTab(viewer)); 1794 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1795 if (dm->fields[f].adjacency[0]) { 1796 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1797 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1798 } else { 1799 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1800 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1801 } 1802 PetscCall(PetscViewerASCIIPopTab(viewer)); 1803 } 1804 } 1805 PetscCall(DMGetCoarseDM(dm, &cdm)); 1806 if (cdm) { 1807 PetscCall(PetscViewerASCIIPushTab(viewer)); 1808 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1809 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1810 PetscCall(PetscViewerASCIIPopTab(viewer)); 1811 } 1812 } 1813 PetscFunctionReturn(PETSC_SUCCESS); 1814 } 1815 1816 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1817 { 1818 DMPolytopeType ct; 1819 PetscMPIInt rank; 1820 PetscInt cdim; 1821 1822 PetscFunctionBegin; 1823 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1824 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1825 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1826 switch (ct) { 1827 case DM_POLYTOPE_SEGMENT: 1828 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1829 switch (cdim) { 1830 case 1: { 1831 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1832 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1833 1834 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1835 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1836 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1837 } break; 1838 case 2: { 1839 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1840 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1841 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1842 1843 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1844 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1845 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1846 } break; 1847 default: 1848 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1849 } 1850 break; 1851 case DM_POLYTOPE_TRIANGLE: 1852 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1853 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1854 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1855 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1856 break; 1857 case DM_POLYTOPE_QUADRILATERAL: 1858 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1859 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1860 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1861 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1862 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1863 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1864 break; 1865 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1866 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1867 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1868 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1869 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1870 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1871 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1872 break; 1873 case DM_POLYTOPE_FV_GHOST: 1874 break; 1875 default: 1876 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1877 } 1878 PetscFunctionReturn(PETSC_SUCCESS); 1879 } 1880 1881 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1882 { 1883 PetscReal centroid[2] = {0., 0.}; 1884 PetscMPIInt rank; 1885 PetscMPIInt fillColor; 1886 1887 PetscFunctionBegin; 1888 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1889 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1890 for (PetscInt v = 0; v < Nv; ++v) { 1891 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1892 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1893 } 1894 for (PetscInt e = 0; e < Nv; ++e) { 1895 refCoords[0] = refVertices[e * 2 + 0]; 1896 refCoords[1] = refVertices[e * 2 + 1]; 1897 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1898 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1899 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1900 } 1901 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1902 for (PetscInt d = 0; d < edgeDiv; ++d) { 1903 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1904 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1905 } 1906 } 1907 PetscFunctionReturn(PETSC_SUCCESS); 1908 } 1909 1910 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1911 { 1912 DMPolytopeType ct; 1913 1914 PetscFunctionBegin; 1915 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1916 switch (ct) { 1917 case DM_POLYTOPE_TRIANGLE: { 1918 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1919 1920 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1921 } break; 1922 case DM_POLYTOPE_QUADRILATERAL: { 1923 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1924 1925 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1926 } break; 1927 default: 1928 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1929 } 1930 PetscFunctionReturn(PETSC_SUCCESS); 1931 } 1932 1933 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1934 { 1935 PetscDraw draw; 1936 DM cdm; 1937 PetscSection coordSection; 1938 Vec coordinates; 1939 PetscReal xyl[3], xyr[3]; 1940 PetscReal *refCoords, *edgeCoords; 1941 PetscBool isnull, drawAffine; 1942 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1943 1944 PetscFunctionBegin; 1945 PetscCall(DMGetCoordinateDim(dm, &dim)); 1946 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1947 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1948 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1949 edgeDiv = cDegree + 1; 1950 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1951 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1952 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1953 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1954 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1955 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1956 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1957 1958 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1959 PetscCall(PetscDrawIsNull(draw, &isnull)); 1960 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1961 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1962 1963 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1964 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1965 PetscCall(PetscDrawClear(draw)); 1966 1967 for (c = cStart; c < cEnd; ++c) { 1968 PetscScalar *coords = NULL; 1969 const PetscScalar *coords_arr; 1970 PetscInt numCoords; 1971 PetscBool isDG; 1972 1973 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1974 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1975 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1976 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1977 } 1978 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1979 PetscCall(PetscDrawFlush(draw)); 1980 PetscCall(PetscDrawPause(draw)); 1981 PetscCall(PetscDrawSave(draw)); 1982 PetscFunctionReturn(PETSC_SUCCESS); 1983 } 1984 1985 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1986 { 1987 DM odm = dm, rdm = dm, cdm; 1988 PetscFE fe; 1989 PetscSpace sp; 1990 PetscClassId id; 1991 PetscInt degree; 1992 PetscBool hoView = PETSC_TRUE; 1993 1994 PetscFunctionBegin; 1995 PetscObjectOptionsBegin((PetscObject)dm); 1996 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1997 PetscOptionsEnd(); 1998 PetscCall(PetscObjectReference((PetscObject)dm)); 1999 *hdm = dm; 2000 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 2001 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2002 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 2003 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 2004 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 2005 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 2006 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 2007 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 2008 DM cdm, rcdm; 2009 Mat In; 2010 Vec cl, rcl; 2011 2012 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 2013 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 2014 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 2015 PetscCall(DMGetCoordinateDM(odm, &cdm)); 2016 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 2017 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 2018 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 2019 PetscCall(DMSetCoarseDM(rcdm, cdm)); 2020 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 2021 PetscCall(MatMult(In, cl, rcl)); 2022 PetscCall(MatDestroy(&In)); 2023 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 2024 PetscCall(DMDestroy(&odm)); 2025 odm = rdm; 2026 } 2027 *hdm = rdm; 2028 PetscFunctionReturn(PETSC_SUCCESS); 2029 } 2030 2031 #if defined(PETSC_HAVE_EXODUSII) 2032 #include <exodusII.h> 2033 #include <petscviewerexodusii.h> 2034 #endif 2035 2036 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 2037 { 2038 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 2039 char name[PETSC_MAX_PATH_LEN]; 2040 2041 PetscFunctionBegin; 2042 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2043 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2044 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 2045 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2046 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2047 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2048 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 2049 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 2050 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 2051 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2052 if (iascii) { 2053 PetscViewerFormat format; 2054 PetscCall(PetscViewerGetFormat(viewer, &format)); 2055 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 2056 else PetscCall(DMPlexView_Ascii(dm, viewer)); 2057 } else if (ishdf5) { 2058 #if defined(PETSC_HAVE_HDF5) 2059 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 2060 #else 2061 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2062 #endif 2063 } else if (isvtk) { 2064 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2065 } else if (isdraw) { 2066 DM hdm; 2067 2068 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2069 PetscCall(DMPlexView_Draw(hdm, viewer)); 2070 PetscCall(DMDestroy(&hdm)); 2071 } else if (isglvis) { 2072 PetscCall(DMPlexView_GLVis(dm, viewer)); 2073 #if defined(PETSC_HAVE_EXODUSII) 2074 } else if (isexodus) { 2075 /* 2076 exodusII requires that all sets be part of exactly one cell set. 2077 If the dm does not have a "Cell Sets" label defined, we create one 2078 with ID 1, containing all cells. 2079 Note that if the Cell Sets label is defined but does not cover all cells, 2080 we may still have a problem. This should probably be checked here or in the viewer; 2081 */ 2082 PetscInt numCS; 2083 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2084 if (!numCS) { 2085 PetscInt cStart, cEnd, c; 2086 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2087 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2088 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2089 } 2090 PetscCall(DMView_PlexExodusII(dm, viewer)); 2091 #endif 2092 #if defined(PETSC_HAVE_CGNS) 2093 } else if (iscgns) { 2094 PetscCall(DMView_PlexCGNS(dm, viewer)); 2095 #endif 2096 } else if (ispython) { 2097 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2098 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2099 /* Optionally view the partition */ 2100 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2101 if (flg) { 2102 Vec ranks; 2103 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2104 PetscCall(VecView(ranks, viewer)); 2105 PetscCall(VecDestroy(&ranks)); 2106 } 2107 /* Optionally view a label */ 2108 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2109 if (flg) { 2110 DMLabel label; 2111 Vec val; 2112 2113 PetscCall(DMGetLabel(dm, name, &label)); 2114 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2115 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2116 PetscCall(VecView(val, viewer)); 2117 PetscCall(VecDestroy(&val)); 2118 } 2119 PetscFunctionReturn(PETSC_SUCCESS); 2120 } 2121 2122 /*@ 2123 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2124 2125 Collective 2126 2127 Input Parameters: 2128 + dm - The `DM` whose topology is to be saved 2129 - viewer - The `PetscViewer` to save it in 2130 2131 Level: advanced 2132 2133 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2134 @*/ 2135 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2136 { 2137 PetscBool ishdf5; 2138 2139 PetscFunctionBegin; 2140 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2141 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2142 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2143 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2144 if (ishdf5) { 2145 #if defined(PETSC_HAVE_HDF5) 2146 PetscViewerFormat format; 2147 PetscCall(PetscViewerGetFormat(viewer, &format)); 2148 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2149 IS globalPointNumbering; 2150 2151 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2152 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2153 PetscCall(ISDestroy(&globalPointNumbering)); 2154 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2155 #else 2156 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2157 #endif 2158 } 2159 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2160 PetscFunctionReturn(PETSC_SUCCESS); 2161 } 2162 2163 /*@ 2164 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2165 2166 Collective 2167 2168 Input Parameters: 2169 + dm - The `DM` whose coordinates are to be saved 2170 - viewer - The `PetscViewer` for saving 2171 2172 Level: advanced 2173 2174 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2175 @*/ 2176 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2177 { 2178 PetscBool ishdf5; 2179 2180 PetscFunctionBegin; 2181 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2182 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2183 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2184 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2185 if (ishdf5) { 2186 #if defined(PETSC_HAVE_HDF5) 2187 PetscViewerFormat format; 2188 PetscCall(PetscViewerGetFormat(viewer, &format)); 2189 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2190 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2191 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2192 #else 2193 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2194 #endif 2195 } 2196 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2197 PetscFunctionReturn(PETSC_SUCCESS); 2198 } 2199 2200 /*@ 2201 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2202 2203 Collective 2204 2205 Input Parameters: 2206 + dm - The `DM` whose labels are to be saved 2207 - viewer - The `PetscViewer` for saving 2208 2209 Level: advanced 2210 2211 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2212 @*/ 2213 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2214 { 2215 PetscBool ishdf5; 2216 2217 PetscFunctionBegin; 2218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2219 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2220 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2221 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2222 if (ishdf5) { 2223 #if defined(PETSC_HAVE_HDF5) 2224 IS globalPointNumbering; 2225 PetscViewerFormat format; 2226 2227 PetscCall(PetscViewerGetFormat(viewer, &format)); 2228 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2229 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2230 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2231 PetscCall(ISDestroy(&globalPointNumbering)); 2232 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2233 #else 2234 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2235 #endif 2236 } 2237 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2238 PetscFunctionReturn(PETSC_SUCCESS); 2239 } 2240 2241 /*@ 2242 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2243 2244 Collective 2245 2246 Input Parameters: 2247 + dm - The `DM` that contains the topology on which the section to be saved is defined 2248 . viewer - The `PetscViewer` for saving 2249 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2250 2251 Level: advanced 2252 2253 Notes: 2254 This function is a wrapper around `PetscSectionView()`; in addition to the raw section, it saves information that associates the section points to the topology (`dm`) points. When the topology (`dm`) and the section are later loaded with `DMPlexTopologyLoad()` and `DMPlexSectionLoad()`, respectively, this information is used to match section points with topology points. 2255 2256 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2257 2258 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2259 @*/ 2260 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2261 { 2262 PetscBool ishdf5; 2263 2264 PetscFunctionBegin; 2265 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2266 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2267 if (!sectiondm) sectiondm = dm; 2268 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2269 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2270 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2271 if (ishdf5) { 2272 #if defined(PETSC_HAVE_HDF5) 2273 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2274 #else 2275 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2276 #endif 2277 } 2278 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2279 PetscFunctionReturn(PETSC_SUCCESS); 2280 } 2281 2282 /*@ 2283 DMPlexGlobalVectorView - Saves a global vector 2284 2285 Collective 2286 2287 Input Parameters: 2288 + dm - The `DM` that represents the topology 2289 . viewer - The `PetscViewer` to save data with 2290 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2291 - vec - The global vector to be saved 2292 2293 Level: advanced 2294 2295 Notes: 2296 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2297 2298 Calling sequence: 2299 .vb 2300 DMCreate(PETSC_COMM_WORLD, &dm); 2301 DMSetType(dm, DMPLEX); 2302 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2303 DMClone(dm, §iondm); 2304 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2305 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2306 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2307 PetscSectionSetChart(section, pStart, pEnd); 2308 PetscSectionSetUp(section); 2309 DMSetLocalSection(sectiondm, section); 2310 PetscSectionDestroy(§ion); 2311 DMGetGlobalVector(sectiondm, &vec); 2312 PetscObjectSetName((PetscObject)vec, "vec_name"); 2313 DMPlexTopologyView(dm, viewer); 2314 DMPlexSectionView(dm, viewer, sectiondm); 2315 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2316 DMRestoreGlobalVector(sectiondm, &vec); 2317 DMDestroy(§iondm); 2318 DMDestroy(&dm); 2319 .ve 2320 2321 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2322 @*/ 2323 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2324 { 2325 PetscBool ishdf5; 2326 2327 PetscFunctionBegin; 2328 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2329 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2330 if (!sectiondm) sectiondm = dm; 2331 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2332 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2333 /* Check consistency */ 2334 { 2335 PetscSection section; 2336 PetscBool includesConstraints; 2337 PetscInt m, m1; 2338 2339 PetscCall(VecGetLocalSize(vec, &m1)); 2340 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2341 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2342 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2343 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2344 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2345 } 2346 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2347 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2348 if (ishdf5) { 2349 #if defined(PETSC_HAVE_HDF5) 2350 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2351 #else 2352 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2353 #endif 2354 } 2355 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2356 PetscFunctionReturn(PETSC_SUCCESS); 2357 } 2358 2359 /*@ 2360 DMPlexLocalVectorView - Saves a local vector 2361 2362 Collective 2363 2364 Input Parameters: 2365 + dm - The `DM` that represents the topology 2366 . viewer - The `PetscViewer` to save data with 2367 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2368 - vec - The local vector to be saved 2369 2370 Level: advanced 2371 2372 Note: 2373 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2374 2375 Calling sequence: 2376 .vb 2377 DMCreate(PETSC_COMM_WORLD, &dm); 2378 DMSetType(dm, DMPLEX); 2379 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2380 DMClone(dm, §iondm); 2381 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2382 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2383 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2384 PetscSectionSetChart(section, pStart, pEnd); 2385 PetscSectionSetUp(section); 2386 DMSetLocalSection(sectiondm, section); 2387 DMGetLocalVector(sectiondm, &vec); 2388 PetscObjectSetName((PetscObject)vec, "vec_name"); 2389 DMPlexTopologyView(dm, viewer); 2390 DMPlexSectionView(dm, viewer, sectiondm); 2391 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2392 DMRestoreLocalVector(sectiondm, &vec); 2393 DMDestroy(§iondm); 2394 DMDestroy(&dm); 2395 .ve 2396 2397 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2398 @*/ 2399 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2400 { 2401 PetscBool ishdf5; 2402 2403 PetscFunctionBegin; 2404 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2405 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2406 if (!sectiondm) sectiondm = dm; 2407 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2408 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2409 /* Check consistency */ 2410 { 2411 PetscSection section; 2412 PetscBool includesConstraints; 2413 PetscInt m, m1; 2414 2415 PetscCall(VecGetLocalSize(vec, &m1)); 2416 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2417 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2418 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2419 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2420 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2421 } 2422 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2423 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2424 if (ishdf5) { 2425 #if defined(PETSC_HAVE_HDF5) 2426 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2427 #else 2428 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2429 #endif 2430 } 2431 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2432 PetscFunctionReturn(PETSC_SUCCESS); 2433 } 2434 2435 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2436 { 2437 PetscBool ishdf5; 2438 2439 PetscFunctionBegin; 2440 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2441 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2442 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2443 if (ishdf5) { 2444 #if defined(PETSC_HAVE_HDF5) 2445 PetscViewerFormat format; 2446 PetscCall(PetscViewerGetFormat(viewer, &format)); 2447 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2448 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2449 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2450 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2451 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2452 PetscFunctionReturn(PETSC_SUCCESS); 2453 #else 2454 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2455 #endif 2456 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2457 } 2458 2459 /*@ 2460 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2461 2462 Collective 2463 2464 Input Parameters: 2465 + dm - The `DM` into which the topology is loaded 2466 - viewer - The `PetscViewer` for the saved topology 2467 2468 Output Parameter: 2469 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; 2470 `NULL` if unneeded 2471 2472 Level: advanced 2473 2474 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2475 `PetscViewer`, `PetscSF` 2476 @*/ 2477 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2478 { 2479 PetscBool ishdf5; 2480 2481 PetscFunctionBegin; 2482 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2483 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2484 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2485 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2486 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2487 if (ishdf5) { 2488 #if defined(PETSC_HAVE_HDF5) 2489 PetscViewerFormat format; 2490 PetscCall(PetscViewerGetFormat(viewer, &format)); 2491 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2492 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2493 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2494 #else 2495 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2496 #endif 2497 } 2498 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2499 PetscFunctionReturn(PETSC_SUCCESS); 2500 } 2501 2502 /*@ 2503 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2504 2505 Collective 2506 2507 Input Parameters: 2508 + dm - The `DM` into which the coordinates are loaded 2509 . viewer - The `PetscViewer` for the saved coordinates 2510 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2511 2512 Level: advanced 2513 2514 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2515 `PetscSF`, `PetscViewer` 2516 @*/ 2517 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2518 { 2519 PetscBool ishdf5; 2520 2521 PetscFunctionBegin; 2522 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2523 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2524 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2525 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2526 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2527 if (ishdf5) { 2528 #if defined(PETSC_HAVE_HDF5) 2529 PetscViewerFormat format; 2530 PetscCall(PetscViewerGetFormat(viewer, &format)); 2531 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2532 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2533 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2534 #else 2535 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2536 #endif 2537 } 2538 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2539 PetscFunctionReturn(PETSC_SUCCESS); 2540 } 2541 2542 /*@ 2543 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2544 2545 Collective 2546 2547 Input Parameters: 2548 + dm - The `DM` into which the labels are loaded 2549 . viewer - The `PetscViewer` for the saved labels 2550 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2551 2552 Level: advanced 2553 2554 Note: 2555 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2556 2557 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2558 `PetscSF`, `PetscViewer` 2559 @*/ 2560 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2561 { 2562 PetscBool ishdf5; 2563 2564 PetscFunctionBegin; 2565 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2566 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2567 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2568 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2569 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2570 if (ishdf5) { 2571 #if defined(PETSC_HAVE_HDF5) 2572 PetscViewerFormat format; 2573 2574 PetscCall(PetscViewerGetFormat(viewer, &format)); 2575 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2576 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2577 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2578 #else 2579 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2580 #endif 2581 } 2582 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2583 PetscFunctionReturn(PETSC_SUCCESS); 2584 } 2585 2586 /*@ 2587 DMPlexSectionLoad - Loads section into a `DMPLEX` 2588 2589 Collective 2590 2591 Input Parameters: 2592 + dm - The `DM` that represents the topology 2593 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2594 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2595 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2596 2597 Output Parameters: 2598 + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed) 2599 - localDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed) 2600 2601 Level: advanced 2602 2603 Notes: 2604 This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2605 2606 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2607 2608 The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2609 2610 Example using 2 processes: 2611 .vb 2612 NX (number of points on dm): 4 2613 sectionA : the on-disk section 2614 vecA : a vector associated with sectionA 2615 sectionB : sectiondm's local section constructed in this function 2616 vecB (local) : a vector associated with sectiondm's local section 2617 vecB (global) : a vector associated with sectiondm's global section 2618 2619 rank 0 rank 1 2620 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2621 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2622 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2623 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2624 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2625 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2626 sectionB->atlasDof : 1 0 1 | 1 3 2627 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2628 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2629 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2630 .ve 2631 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2632 2633 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2634 @*/ 2635 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, PeOp DM sectiondm, PetscSF globalToLocalPointSF, PeOp PetscSF *globalDofSF, PeOp PetscSF *localDofSF) 2636 { 2637 PetscBool ishdf5; 2638 2639 PetscFunctionBegin; 2640 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2641 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2642 if (!sectiondm) sectiondm = dm; 2643 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2644 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2645 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2646 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2647 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2648 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2649 if (ishdf5) { 2650 #if defined(PETSC_HAVE_HDF5) 2651 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2652 #else 2653 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2654 #endif 2655 } 2656 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2657 PetscFunctionReturn(PETSC_SUCCESS); 2658 } 2659 2660 /*@ 2661 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2662 2663 Collective 2664 2665 Input Parameters: 2666 + dm - The `DM` that represents the topology 2667 . viewer - The `PetscViewer` that represents the on-disk vector data 2668 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2669 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2670 - vec - The global vector to set values of 2671 2672 Level: advanced 2673 2674 Notes: 2675 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2676 2677 Calling sequence: 2678 .vb 2679 DMCreate(PETSC_COMM_WORLD, &dm); 2680 DMSetType(dm, DMPLEX); 2681 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2682 DMPlexTopologyLoad(dm, viewer, &sfX); 2683 DMClone(dm, §iondm); 2684 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2685 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2686 DMGetGlobalVector(sectiondm, &vec); 2687 PetscObjectSetName((PetscObject)vec, "vec_name"); 2688 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2689 DMRestoreGlobalVector(sectiondm, &vec); 2690 PetscSFDestroy(&gsf); 2691 PetscSFDestroy(&sfX); 2692 DMDestroy(§iondm); 2693 DMDestroy(&dm); 2694 .ve 2695 2696 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2697 `PetscSF`, `PetscViewer` 2698 @*/ 2699 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2700 { 2701 PetscBool ishdf5; 2702 2703 PetscFunctionBegin; 2704 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2705 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2706 if (!sectiondm) sectiondm = dm; 2707 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2708 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2709 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2710 /* Check consistency */ 2711 { 2712 PetscSection section; 2713 PetscBool includesConstraints; 2714 PetscInt m, m1; 2715 2716 PetscCall(VecGetLocalSize(vec, &m1)); 2717 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2718 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2719 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2720 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2721 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2722 } 2723 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2724 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2725 if (ishdf5) { 2726 #if defined(PETSC_HAVE_HDF5) 2727 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2728 #else 2729 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2730 #endif 2731 } 2732 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2733 PetscFunctionReturn(PETSC_SUCCESS); 2734 } 2735 2736 /*@ 2737 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2738 2739 Collective 2740 2741 Input Parameters: 2742 + dm - The `DM` that represents the topology 2743 . viewer - The `PetscViewer` that represents the on-disk vector data 2744 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2745 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2746 - vec - The local vector to set values of 2747 2748 Level: advanced 2749 2750 Notes: 2751 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2752 2753 Calling sequence: 2754 .vb 2755 DMCreate(PETSC_COMM_WORLD, &dm); 2756 DMSetType(dm, DMPLEX); 2757 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2758 DMPlexTopologyLoad(dm, viewer, &sfX); 2759 DMClone(dm, §iondm); 2760 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2761 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2762 DMGetLocalVector(sectiondm, &vec); 2763 PetscObjectSetName((PetscObject)vec, "vec_name"); 2764 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2765 DMRestoreLocalVector(sectiondm, &vec); 2766 PetscSFDestroy(&lsf); 2767 PetscSFDestroy(&sfX); 2768 DMDestroy(§iondm); 2769 DMDestroy(&dm); 2770 .ve 2771 2772 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2773 `PetscSF`, `PetscViewer` 2774 @*/ 2775 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2776 { 2777 PetscBool ishdf5; 2778 2779 PetscFunctionBegin; 2780 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2781 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2782 if (!sectiondm) sectiondm = dm; 2783 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2784 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2785 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2786 /* Check consistency */ 2787 { 2788 PetscSection section; 2789 PetscBool includesConstraints; 2790 PetscInt m, m1; 2791 2792 PetscCall(VecGetLocalSize(vec, &m1)); 2793 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2794 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2795 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2796 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2797 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2798 } 2799 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2800 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2801 if (ishdf5) { 2802 #if defined(PETSC_HAVE_HDF5) 2803 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2804 #else 2805 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2806 #endif 2807 } 2808 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2809 PetscFunctionReturn(PETSC_SUCCESS); 2810 } 2811 2812 PetscErrorCode DMDestroy_Plex(DM dm) 2813 { 2814 DM_Plex *mesh = (DM_Plex *)dm->data; 2815 2816 PetscFunctionBegin; 2817 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2818 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2819 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2820 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2821 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2822 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2823 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2824 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2825 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2826 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2827 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2828 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2829 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2830 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2831 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2832 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2833 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2834 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2835 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2836 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2837 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2838 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2839 PetscCall(PetscFree(mesh->cones)); 2840 PetscCall(PetscFree(mesh->coneOrientations)); 2841 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2842 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2843 PetscCall(PetscFree(mesh->supports)); 2844 PetscCall(PetscFree(mesh->cellTypes)); 2845 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2846 PetscCall(PetscFree(mesh->tetgenOpts)); 2847 PetscCall(PetscFree(mesh->triangleOpts)); 2848 PetscCall(PetscFree(mesh->transformType)); 2849 PetscCall(PetscFree(mesh->distributionName)); 2850 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2851 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2852 PetscCall(ISDestroy(&mesh->subpointIS)); 2853 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2854 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2855 if (mesh->periodic.face_sfs) { 2856 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2857 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2858 } 2859 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2860 if (mesh->periodic.periodic_points) { 2861 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2862 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2863 } 2864 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2865 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2866 PetscCall(ISDestroy(&mesh->anchorIS)); 2867 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2868 PetscCall(PetscFree(mesh->parents)); 2869 PetscCall(PetscFree(mesh->childIDs)); 2870 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2871 PetscCall(PetscFree(mesh->children)); 2872 PetscCall(DMDestroy(&mesh->referenceTree)); 2873 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2874 PetscCall(PetscFree(mesh->neighbors)); 2875 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2876 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2877 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2878 PetscCall(PetscFree(mesh)); 2879 PetscFunctionReturn(PETSC_SUCCESS); 2880 } 2881 2882 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2883 { 2884 PetscSection sectionGlobal, sectionLocal; 2885 PetscInt bs = -1, mbs; 2886 PetscInt localSize, localStart = 0; 2887 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2888 MatType mtype; 2889 ISLocalToGlobalMapping ltog; 2890 2891 PetscFunctionBegin; 2892 PetscCall(MatInitializePackage()); 2893 mtype = dm->mattype; 2894 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2895 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2896 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2897 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2898 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2899 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2900 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2901 PetscCall(MatSetType(*J, mtype)); 2902 PetscCall(MatSetFromOptions(*J)); 2903 PetscCall(MatGetBlockSize(*J, &mbs)); 2904 if (mbs > 1) bs = mbs; 2905 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2906 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2907 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2908 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2909 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2910 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2911 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2912 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2913 if (!isShell) { 2914 // There are three states with pblocks, since block starts can have no dofs: 2915 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2916 // TRUE) Block Start: The first entry in a block has been added 2917 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2918 PetscBT blst; 2919 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2920 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2921 const PetscInt *perm = NULL; 2922 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2923 PetscInt pStart, pEnd, dof, cdof, num_fields; 2924 2925 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2926 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2927 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2928 2929 PetscCall(PetscCalloc1(localSize, &pblocks)); 2930 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2931 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2932 // We need to process in the permuted order to get block sizes right 2933 for (PetscInt point = pStart; point < pEnd; ++point) { 2934 const PetscInt p = perm ? perm[point] : point; 2935 2936 switch (dm->blocking_type) { 2937 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2938 PetscInt bdof, offset; 2939 2940 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2941 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2942 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2943 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2944 if (dof > 0) { 2945 // State change 2946 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2947 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2948 2949 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2950 // Signal block concatenation 2951 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2952 } 2953 dof = dof < 0 ? -(dof + 1) : dof; 2954 bdof = cdof && (dof - cdof) ? 1 : dof; 2955 if (dof) { 2956 if (bs < 0) { 2957 bs = bdof; 2958 } else if (bs != bdof) { 2959 bs = 1; 2960 } 2961 } 2962 } break; 2963 case DM_BLOCKING_FIELD_NODE: { 2964 for (PetscInt field = 0; field < num_fields; field++) { 2965 PetscInt num_comp, bdof, offset; 2966 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2967 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2968 if (dof < 0) continue; 2969 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2970 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2971 PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp); 2972 PetscInt num_nodes = dof / num_comp; 2973 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2974 // Handle possibly constant block size (unlikely) 2975 bdof = cdof && (dof - cdof) ? 1 : dof; 2976 if (dof) { 2977 if (bs < 0) { 2978 bs = bdof; 2979 } else if (bs != bdof) { 2980 bs = 1; 2981 } 2982 } 2983 } 2984 } break; 2985 } 2986 } 2987 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2988 /* Must have same blocksize on all procs (some might have no points) */ 2989 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 2990 bsLocal[1] = bs; 2991 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2992 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2993 else bs = bsMinMax[0]; 2994 bs = PetscMax(1, bs); 2995 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2996 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2997 PetscCall(MatSetBlockSize(*J, bs)); 2998 PetscCall(MatSetUp(*J)); 2999 } else { 3000 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 3001 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 3002 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 3003 } 3004 if (pblocks) { // Consolidate blocks 3005 PetscInt nblocks = 0; 3006 pblocks[0] = PetscAbs(pblocks[0]); 3007 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 3008 if (pblocks[i] == 0) continue; 3009 // Negative block size indicates the blocks should be concatenated 3010 if (pblocks[i] < 0) { 3011 pblocks[i] = -pblocks[i]; 3012 pblocks[nblocks - 1] += pblocks[i]; 3013 } else { 3014 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 3015 } 3016 for (PetscInt j = 1; j < pblocks[i]; j++) 3017 PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j); 3018 } 3019 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 3020 } 3021 PetscCall(PetscFree(pblocks)); 3022 } 3023 PetscCall(MatSetDM(*J, dm)); 3024 PetscFunctionReturn(PETSC_SUCCESS); 3025 } 3026 3027 /*@ 3028 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 3029 3030 Not Collective 3031 3032 Input Parameter: 3033 . dm - The `DMPLEX` 3034 3035 Output Parameter: 3036 . subsection - The subdomain section 3037 3038 Level: developer 3039 3040 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 3041 @*/ 3042 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 3043 { 3044 DM_Plex *mesh = (DM_Plex *)dm->data; 3045 3046 PetscFunctionBegin; 3047 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3048 if (!mesh->subdomainSection) { 3049 PetscSection section; 3050 PetscSF sf; 3051 3052 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 3053 PetscCall(DMGetLocalSection(dm, §ion)); 3054 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 3055 PetscCall(PetscSFDestroy(&sf)); 3056 } 3057 *subsection = mesh->subdomainSection; 3058 PetscFunctionReturn(PETSC_SUCCESS); 3059 } 3060 3061 /*@ 3062 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 3063 3064 Not Collective 3065 3066 Input Parameter: 3067 . dm - The `DMPLEX` 3068 3069 Output Parameters: 3070 + pStart - The first mesh point 3071 - pEnd - The upper bound for mesh points 3072 3073 Level: beginner 3074 3075 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3076 @*/ 3077 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3078 { 3079 DM_Plex *mesh = (DM_Plex *)dm->data; 3080 3081 PetscFunctionBegin; 3082 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3083 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3084 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3085 PetscFunctionReturn(PETSC_SUCCESS); 3086 } 3087 3088 /*@ 3089 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3090 3091 Not Collective 3092 3093 Input Parameters: 3094 + dm - The `DMPLEX` 3095 . pStart - The first mesh point 3096 - pEnd - The upper bound for mesh points 3097 3098 Level: beginner 3099 3100 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3101 @*/ 3102 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3103 { 3104 DM_Plex *mesh = (DM_Plex *)dm->data; 3105 3106 PetscFunctionBegin; 3107 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3108 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3109 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3110 PetscCall(PetscFree(mesh->cellTypes)); 3111 PetscFunctionReturn(PETSC_SUCCESS); 3112 } 3113 3114 /*@ 3115 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3116 3117 Not Collective 3118 3119 Input Parameters: 3120 + dm - The `DMPLEX` 3121 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3122 3123 Output Parameter: 3124 . size - The cone size for point `p` 3125 3126 Level: beginner 3127 3128 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3129 @*/ 3130 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3131 { 3132 DM_Plex *mesh = (DM_Plex *)dm->data; 3133 3134 PetscFunctionBegin; 3135 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3136 PetscAssertPointer(size, 3); 3137 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3138 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3139 PetscFunctionReturn(PETSC_SUCCESS); 3140 } 3141 3142 /*@ 3143 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3144 3145 Not Collective 3146 3147 Input Parameters: 3148 + dm - The `DMPLEX` 3149 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3150 - size - The cone size for point `p` 3151 3152 Level: beginner 3153 3154 Note: 3155 This should be called after `DMPlexSetChart()`. 3156 3157 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3158 @*/ 3159 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3160 { 3161 DM_Plex *mesh = (DM_Plex *)dm->data; 3162 3163 PetscFunctionBegin; 3164 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3165 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3166 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3167 PetscFunctionReturn(PETSC_SUCCESS); 3168 } 3169 3170 /*@C 3171 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3172 3173 Not Collective 3174 3175 Input Parameters: 3176 + dm - The `DMPLEX` 3177 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3178 3179 Output Parameter: 3180 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3181 3182 Level: beginner 3183 3184 Fortran Notes: 3185 `cone` must be declared with 3186 .vb 3187 PetscInt, pointer :: cone(:) 3188 .ve 3189 3190 You must call `DMPlexRestoreCone()` after you finish using the array. 3191 `DMPlexRestoreCone()` is not needed/available in C. 3192 3193 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3194 @*/ 3195 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3196 { 3197 DM_Plex *mesh = (DM_Plex *)dm->data; 3198 PetscInt off; 3199 3200 PetscFunctionBegin; 3201 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3202 PetscAssertPointer(cone, 3); 3203 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3204 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3205 PetscFunctionReturn(PETSC_SUCCESS); 3206 } 3207 3208 /*@ 3209 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3210 3211 Not Collective 3212 3213 Input Parameters: 3214 + dm - The `DMPLEX` 3215 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3216 3217 Output Parameters: 3218 + pConesSection - `PetscSection` describing the layout of `pCones` 3219 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3220 3221 Level: intermediate 3222 3223 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3224 @*/ 3225 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PeOp PetscSection *pConesSection, PeOp IS *pCones) 3226 { 3227 PetscSection cs, newcs; 3228 PetscInt *cones; 3229 PetscInt *newarr = NULL; 3230 PetscInt n; 3231 3232 PetscFunctionBegin; 3233 PetscCall(DMPlexGetCones(dm, &cones)); 3234 PetscCall(DMPlexGetConeSection(dm, &cs)); 3235 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3236 if (pConesSection) *pConesSection = newcs; 3237 if (pCones) { 3238 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3239 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3240 } 3241 PetscFunctionReturn(PETSC_SUCCESS); 3242 } 3243 3244 /*@ 3245 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3246 3247 Not Collective 3248 3249 Input Parameters: 3250 + dm - The `DMPLEX` 3251 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3252 3253 Output Parameter: 3254 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3255 3256 Level: advanced 3257 3258 Notes: 3259 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3260 3261 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3262 3263 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3264 `DMPlexGetDepth()`, `IS` 3265 @*/ 3266 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3267 { 3268 IS *expandedPointsAll; 3269 PetscInt depth; 3270 3271 PetscFunctionBegin; 3272 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3273 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3274 PetscAssertPointer(expandedPoints, 3); 3275 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3276 *expandedPoints = expandedPointsAll[0]; 3277 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3278 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3279 PetscFunctionReturn(PETSC_SUCCESS); 3280 } 3281 3282 /*@ 3283 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3284 (DAG points of depth 0, i.e., without cones). 3285 3286 Not Collective 3287 3288 Input Parameters: 3289 + dm - The `DMPLEX` 3290 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3291 3292 Output Parameters: 3293 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3294 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3295 - sections - (optional) An array of sections which describe mappings from points to their cone points 3296 3297 Level: advanced 3298 3299 Notes: 3300 Like `DMPlexGetConeTuple()` but recursive. 3301 3302 Array `expandedPoints` has size equal to `depth`. Each `expandedPoints`[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 3303 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3304 3305 Array section has size equal to `depth`. Each `PetscSection` `sections`[d] realizes mapping from `expandedPoints`[d+1] (section points) to `expandedPoints`[d] (section dofs) as follows\: 3306 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3307 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3308 3309 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3310 `DMPlexGetDepth()`, `PetscSection`, `IS` 3311 @*/ 3312 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3313 { 3314 const PetscInt *arr0 = NULL, *cone = NULL; 3315 PetscInt *arr = NULL, *newarr = NULL; 3316 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3317 IS *expandedPoints_; 3318 PetscSection *sections_; 3319 3320 PetscFunctionBegin; 3321 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3322 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3323 if (depth) PetscAssertPointer(depth, 3); 3324 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3325 if (sections) PetscAssertPointer(sections, 5); 3326 PetscCall(ISGetLocalSize(points, &n)); 3327 PetscCall(ISGetIndices(points, &arr0)); 3328 PetscCall(DMPlexGetDepth(dm, &depth_)); 3329 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3330 PetscCall(PetscCalloc1(depth_, §ions_)); 3331 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3332 for (d = depth_ - 1; d >= 0; d--) { 3333 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3334 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3335 for (i = 0; i < n; i++) { 3336 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3337 if (arr[i] >= start && arr[i] < end) { 3338 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3339 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3340 } else { 3341 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3342 } 3343 } 3344 PetscCall(PetscSectionSetUp(sections_[d])); 3345 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3346 PetscCall(PetscMalloc1(newn, &newarr)); 3347 for (i = 0; i < n; i++) { 3348 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3349 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3350 if (cn > 1) { 3351 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3352 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3353 } else { 3354 newarr[co] = arr[i]; 3355 } 3356 } 3357 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3358 arr = newarr; 3359 n = newn; 3360 } 3361 PetscCall(ISRestoreIndices(points, &arr0)); 3362 *depth = depth_; 3363 if (expandedPoints) *expandedPoints = expandedPoints_; 3364 else { 3365 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3366 PetscCall(PetscFree(expandedPoints_)); 3367 } 3368 if (sections) *sections = sections_; 3369 else { 3370 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3371 PetscCall(PetscFree(sections_)); 3372 } 3373 PetscFunctionReturn(PETSC_SUCCESS); 3374 } 3375 3376 /*@ 3377 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3378 3379 Not Collective 3380 3381 Input Parameters: 3382 + dm - The `DMPLEX` 3383 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3384 3385 Output Parameters: 3386 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3387 . expandedPoints - (optional) An array of recursively expanded cones 3388 - sections - (optional) An array of sections which describe mappings from points to their cone points 3389 3390 Level: advanced 3391 3392 Note: 3393 See `DMPlexGetConeRecursive()` 3394 3395 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3396 `DMPlexGetDepth()`, `IS`, `PetscSection` 3397 @*/ 3398 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3399 { 3400 PetscInt d, depth_; 3401 3402 PetscFunctionBegin; 3403 PetscCall(DMPlexGetDepth(dm, &depth_)); 3404 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3405 if (depth) *depth = 0; 3406 if (expandedPoints) { 3407 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3408 PetscCall(PetscFree(*expandedPoints)); 3409 } 3410 if (sections) { 3411 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3412 PetscCall(PetscFree(*sections)); 3413 } 3414 PetscFunctionReturn(PETSC_SUCCESS); 3415 } 3416 3417 /*@ 3418 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 3419 3420 Not Collective 3421 3422 Input Parameters: 3423 + dm - The `DMPLEX` 3424 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3425 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3426 3427 Level: beginner 3428 3429 Note: 3430 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3431 3432 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3433 @*/ 3434 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3435 { 3436 DM_Plex *mesh = (DM_Plex *)dm->data; 3437 PetscInt dof, off, c; 3438 3439 PetscFunctionBegin; 3440 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3441 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3442 if (dof) PetscAssertPointer(cone, 3); 3443 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3444 if (PetscDefined(USE_DEBUG)) { 3445 PetscInt pStart, pEnd; 3446 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3447 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3448 for (c = 0; c < dof; ++c) { 3449 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3450 mesh->cones[off + c] = cone[c]; 3451 } 3452 } else { 3453 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3454 } 3455 PetscFunctionReturn(PETSC_SUCCESS); 3456 } 3457 3458 /*@C 3459 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3460 3461 Not Collective 3462 3463 Input Parameters: 3464 + dm - The `DMPLEX` 3465 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3466 3467 Output Parameter: 3468 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3469 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3470 3471 Level: beginner 3472 3473 Note: 3474 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3475 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3476 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3477 with the identity. 3478 3479 Fortran Notes: 3480 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3481 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3482 3483 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3484 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3485 @*/ 3486 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3487 { 3488 DM_Plex *mesh = (DM_Plex *)dm->data; 3489 PetscInt off; 3490 3491 PetscFunctionBegin; 3492 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3493 if (PetscDefined(USE_DEBUG)) { 3494 PetscInt dof; 3495 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3496 if (dof) PetscAssertPointer(coneOrientation, 3); 3497 } 3498 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3499 3500 *coneOrientation = &mesh->coneOrientations[off]; 3501 PetscFunctionReturn(PETSC_SUCCESS); 3502 } 3503 3504 /*@ 3505 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3506 3507 Not Collective 3508 3509 Input Parameters: 3510 + dm - The `DMPLEX` 3511 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3512 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3513 3514 Level: beginner 3515 3516 Notes: 3517 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3518 3519 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3520 3521 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3522 @*/ 3523 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3524 { 3525 DM_Plex *mesh = (DM_Plex *)dm->data; 3526 PetscInt pStart, pEnd; 3527 PetscInt dof, off, c; 3528 3529 PetscFunctionBegin; 3530 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3531 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3532 if (dof) PetscAssertPointer(coneOrientation, 3); 3533 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3534 if (PetscDefined(USE_DEBUG)) { 3535 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3536 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3537 for (c = 0; c < dof; ++c) { 3538 PetscInt cdof, o = coneOrientation[c]; 3539 3540 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3541 PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof); 3542 mesh->coneOrientations[off + c] = o; 3543 } 3544 } else { 3545 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3546 } 3547 PetscFunctionReturn(PETSC_SUCCESS); 3548 } 3549 3550 /*@ 3551 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3552 3553 Not Collective 3554 3555 Input Parameters: 3556 + dm - The `DMPLEX` 3557 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3558 . conePos - The local index in the cone where the point should be put 3559 - conePoint - The mesh point to insert 3560 3561 Level: beginner 3562 3563 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3564 @*/ 3565 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3566 { 3567 DM_Plex *mesh = (DM_Plex *)dm->data; 3568 PetscInt pStart, pEnd; 3569 PetscInt dof, off; 3570 3571 PetscFunctionBegin; 3572 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3573 if (PetscDefined(USE_DEBUG)) { 3574 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3575 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3576 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3577 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3578 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3579 } 3580 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3581 mesh->cones[off + conePos] = conePoint; 3582 PetscFunctionReturn(PETSC_SUCCESS); 3583 } 3584 3585 /*@ 3586 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3587 3588 Not Collective 3589 3590 Input Parameters: 3591 + dm - The `DMPLEX` 3592 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3593 . conePos - The local index in the cone where the point should be put 3594 - coneOrientation - The point orientation to insert 3595 3596 Level: beginner 3597 3598 Note: 3599 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3600 3601 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3602 @*/ 3603 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3604 { 3605 DM_Plex *mesh = (DM_Plex *)dm->data; 3606 PetscInt pStart, pEnd; 3607 PetscInt dof, off; 3608 3609 PetscFunctionBegin; 3610 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3611 if (PetscDefined(USE_DEBUG)) { 3612 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3613 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3614 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3615 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3616 } 3617 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3618 mesh->coneOrientations[off + conePos] = coneOrientation; 3619 PetscFunctionReturn(PETSC_SUCCESS); 3620 } 3621 3622 /*@C 3623 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3624 3625 Not collective 3626 3627 Input Parameters: 3628 + dm - The DMPlex 3629 - p - The point, which must lie in the chart set with DMPlexSetChart() 3630 3631 Output Parameters: 3632 + cone - An array of points which are on the in-edges for point `p` 3633 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3634 integer giving the prescription for cone traversal. 3635 3636 Level: beginner 3637 3638 Notes: 3639 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3640 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3641 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3642 with the identity. 3643 3644 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3645 3646 Fortran Notes: 3647 `cone` and `ornt` must be declared with 3648 .vb 3649 PetscInt, pointer :: cone(:) 3650 PetscInt, pointer :: ornt(:) 3651 .ve 3652 3653 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3654 @*/ 3655 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, PeOp const PetscInt *cone[], PeOp const PetscInt *ornt[]) 3656 { 3657 DM_Plex *mesh = (DM_Plex *)dm->data; 3658 3659 PetscFunctionBegin; 3660 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3661 if (mesh->tr) { 3662 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3663 } else { 3664 PetscInt off; 3665 if (PetscDefined(USE_DEBUG)) { 3666 PetscInt dof; 3667 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3668 if (dof) { 3669 if (cone) PetscAssertPointer(cone, 3); 3670 if (ornt) PetscAssertPointer(ornt, 4); 3671 } 3672 } 3673 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3674 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3675 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3676 } 3677 PetscFunctionReturn(PETSC_SUCCESS); 3678 } 3679 3680 /*@C 3681 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3682 3683 Not Collective 3684 3685 Input Parameters: 3686 + dm - The DMPlex 3687 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3688 . cone - An array of points which are on the in-edges for point p 3689 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3690 integer giving the prescription for cone traversal. 3691 3692 Level: beginner 3693 3694 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3695 @*/ 3696 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3697 { 3698 DM_Plex *mesh = (DM_Plex *)dm->data; 3699 3700 PetscFunctionBegin; 3701 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3702 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3703 PetscFunctionReturn(PETSC_SUCCESS); 3704 } 3705 3706 /*@ 3707 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3708 3709 Not Collective 3710 3711 Input Parameters: 3712 + dm - The `DMPLEX` 3713 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3714 3715 Output Parameter: 3716 . size - The support size for point `p` 3717 3718 Level: beginner 3719 3720 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3721 @*/ 3722 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3723 { 3724 DM_Plex *mesh = (DM_Plex *)dm->data; 3725 3726 PetscFunctionBegin; 3727 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3728 PetscAssertPointer(size, 3); 3729 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3730 PetscFunctionReturn(PETSC_SUCCESS); 3731 } 3732 3733 /*@ 3734 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3735 3736 Not Collective 3737 3738 Input Parameters: 3739 + dm - The `DMPLEX` 3740 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3741 - size - The support size for point `p` 3742 3743 Level: beginner 3744 3745 Note: 3746 This should be called after `DMPlexSetChart()`. 3747 3748 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3749 @*/ 3750 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3751 { 3752 DM_Plex *mesh = (DM_Plex *)dm->data; 3753 3754 PetscFunctionBegin; 3755 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3756 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3757 PetscFunctionReturn(PETSC_SUCCESS); 3758 } 3759 3760 /*@C 3761 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3762 3763 Not Collective 3764 3765 Input Parameters: 3766 + dm - The `DMPLEX` 3767 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3768 3769 Output Parameter: 3770 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3771 3772 Level: beginner 3773 3774 Fortran Notes: 3775 `support` must be declared with 3776 .vb 3777 PetscInt, pointer :: support(:) 3778 .ve 3779 3780 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3781 `DMPlexRestoreSupport()` is not needed/available in C. 3782 3783 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3784 @*/ 3785 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3786 { 3787 DM_Plex *mesh = (DM_Plex *)dm->data; 3788 PetscInt off; 3789 3790 PetscFunctionBegin; 3791 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3792 PetscAssertPointer(support, 3); 3793 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3794 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3795 PetscFunctionReturn(PETSC_SUCCESS); 3796 } 3797 3798 /*@ 3799 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3800 3801 Not Collective 3802 3803 Input Parameters: 3804 + dm - The `DMPLEX` 3805 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3806 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3807 3808 Level: beginner 3809 3810 Note: 3811 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3812 3813 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3814 @*/ 3815 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3816 { 3817 DM_Plex *mesh = (DM_Plex *)dm->data; 3818 PetscInt pStart, pEnd; 3819 PetscInt dof, off, c; 3820 3821 PetscFunctionBegin; 3822 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3823 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3824 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3825 if (dof) PetscAssertPointer(support, 3); 3826 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3827 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3828 for (c = 0; c < dof; ++c) { 3829 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3830 mesh->supports[off + c] = support[c]; 3831 } 3832 PetscFunctionReturn(PETSC_SUCCESS); 3833 } 3834 3835 /*@ 3836 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3837 3838 Not Collective 3839 3840 Input Parameters: 3841 + dm - The `DMPLEX` 3842 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3843 . supportPos - The local index in the cone where the point should be put 3844 - supportPoint - The mesh point to insert 3845 3846 Level: beginner 3847 3848 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3849 @*/ 3850 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3851 { 3852 DM_Plex *mesh = (DM_Plex *)dm->data; 3853 PetscInt pStart, pEnd; 3854 PetscInt dof, off; 3855 3856 PetscFunctionBegin; 3857 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3858 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3859 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3860 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3861 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3862 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3863 PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3864 mesh->supports[off + supportPos] = supportPoint; 3865 PetscFunctionReturn(PETSC_SUCCESS); 3866 } 3867 3868 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3869 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3870 { 3871 switch (ct) { 3872 case DM_POLYTOPE_SEGMENT: 3873 if (o == -1) return -2; 3874 break; 3875 case DM_POLYTOPE_TRIANGLE: 3876 if (o == -3) return -1; 3877 if (o == -2) return -3; 3878 if (o == -1) return -2; 3879 break; 3880 case DM_POLYTOPE_QUADRILATERAL: 3881 if (o == -4) return -2; 3882 if (o == -3) return -1; 3883 if (o == -2) return -4; 3884 if (o == -1) return -3; 3885 break; 3886 default: 3887 return o; 3888 } 3889 return o; 3890 } 3891 3892 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3893 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3894 { 3895 switch (ct) { 3896 case DM_POLYTOPE_SEGMENT: 3897 if ((o == -2) || (o == 1)) return -1; 3898 if (o == -1) return 0; 3899 break; 3900 case DM_POLYTOPE_TRIANGLE: 3901 if (o == -3) return -2; 3902 if (o == -2) return -1; 3903 if (o == -1) return -3; 3904 break; 3905 case DM_POLYTOPE_QUADRILATERAL: 3906 if (o == -4) return -2; 3907 if (o == -3) return -1; 3908 if (o == -2) return -4; 3909 if (o == -1) return -3; 3910 break; 3911 default: 3912 return o; 3913 } 3914 return o; 3915 } 3916 3917 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3918 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3919 { 3920 PetscInt pStart, pEnd, p; 3921 3922 PetscFunctionBegin; 3923 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3924 for (p = pStart; p < pEnd; ++p) { 3925 const PetscInt *cone, *ornt; 3926 PetscInt coneSize, c; 3927 3928 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3929 PetscCall(DMPlexGetCone(dm, p, &cone)); 3930 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3931 for (c = 0; c < coneSize; ++c) { 3932 DMPolytopeType ct; 3933 const PetscInt o = ornt[c]; 3934 3935 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3936 switch (ct) { 3937 case DM_POLYTOPE_SEGMENT: 3938 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3939 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3940 break; 3941 case DM_POLYTOPE_TRIANGLE: 3942 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3943 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3944 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3945 break; 3946 case DM_POLYTOPE_QUADRILATERAL: 3947 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3948 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3949 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3950 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3951 break; 3952 default: 3953 break; 3954 } 3955 } 3956 } 3957 PetscFunctionReturn(PETSC_SUCCESS); 3958 } 3959 3960 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3961 { 3962 DM_Plex *mesh = (DM_Plex *)dm->data; 3963 3964 PetscFunctionBeginHot; 3965 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3966 if (useCone) { 3967 PetscCall(DMPlexGetConeSize(dm, p, size)); 3968 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3969 } else { 3970 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3971 PetscCall(DMPlexGetSupport(dm, p, arr)); 3972 } 3973 } else { 3974 if (useCone) { 3975 const PetscSection s = mesh->coneSection; 3976 const PetscInt ps = p - s->pStart; 3977 const PetscInt off = s->atlasOff[ps]; 3978 3979 *size = s->atlasDof[ps]; 3980 *arr = mesh->cones + off; 3981 *ornt = mesh->coneOrientations + off; 3982 } else { 3983 const PetscSection s = mesh->supportSection; 3984 const PetscInt ps = p - s->pStart; 3985 const PetscInt off = s->atlasOff[ps]; 3986 3987 *size = s->atlasDof[ps]; 3988 *arr = mesh->supports + off; 3989 } 3990 } 3991 PetscFunctionReturn(PETSC_SUCCESS); 3992 } 3993 3994 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3995 { 3996 DM_Plex *mesh = (DM_Plex *)dm->data; 3997 3998 PetscFunctionBeginHot; 3999 if (PetscDefined(USE_DEBUG) || mesh->tr) { 4000 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 4001 } 4002 PetscFunctionReturn(PETSC_SUCCESS); 4003 } 4004 4005 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4006 { 4007 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4008 PetscInt *closure; 4009 const PetscInt *tmp = NULL, *tmpO = NULL; 4010 PetscInt off = 0, tmpSize, t; 4011 4012 PetscFunctionBeginHot; 4013 if (ornt) { 4014 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4015 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 4016 } 4017 if (*points) { 4018 closure = *points; 4019 } else { 4020 PetscInt maxConeSize, maxSupportSize; 4021 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4022 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 4023 } 4024 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4025 if (ct == DM_POLYTOPE_UNKNOWN) { 4026 closure[off++] = p; 4027 closure[off++] = 0; 4028 for (t = 0; t < tmpSize; ++t) { 4029 closure[off++] = tmp[t]; 4030 closure[off++] = tmpO ? tmpO[t] : 0; 4031 } 4032 } else { 4033 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 4034 4035 /* We assume that cells with a valid type have faces with a valid type */ 4036 closure[off++] = p; 4037 closure[off++] = ornt; 4038 for (t = 0; t < tmpSize; ++t) { 4039 DMPolytopeType ft; 4040 4041 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 4042 closure[off++] = tmp[arr[t]]; 4043 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 4044 } 4045 } 4046 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4047 if (numPoints) *numPoints = tmpSize + 1; 4048 if (points) *points = closure; 4049 PetscFunctionReturn(PETSC_SUCCESS); 4050 } 4051 4052 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 4053 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 4054 { 4055 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 4056 const PetscInt *cone, *ornt; 4057 PetscInt *pts, *closure = NULL; 4058 DMPolytopeType ft; 4059 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 4060 PetscInt dim, coneSize, c, d, clSize, cl; 4061 4062 PetscFunctionBeginHot; 4063 PetscCall(DMGetDimension(dm, &dim)); 4064 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4065 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4066 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4067 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4068 maxSize = PetscMax(coneSeries, supportSeries); 4069 if (*points) { 4070 pts = *points; 4071 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4072 c = 0; 4073 pts[c++] = point; 4074 pts[c++] = o; 4075 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4076 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4077 for (cl = 0; cl < clSize * 2; cl += 2) { 4078 pts[c++] = closure[cl]; 4079 pts[c++] = closure[cl + 1]; 4080 } 4081 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4082 for (cl = 0; cl < clSize * 2; cl += 2) { 4083 pts[c++] = closure[cl]; 4084 pts[c++] = closure[cl + 1]; 4085 } 4086 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4087 for (d = 2; d < coneSize; ++d) { 4088 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4089 pts[c++] = cone[arr[d * 2 + 0]]; 4090 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4091 } 4092 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4093 if (dim >= 3) { 4094 for (d = 2; d < coneSize; ++d) { 4095 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4096 const PetscInt *fcone, *fornt; 4097 PetscInt fconeSize, fc, i; 4098 4099 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4100 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4101 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4102 for (fc = 0; fc < fconeSize; ++fc) { 4103 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4104 const PetscInt co = farr[fc * 2 + 1]; 4105 4106 for (i = 0; i < c; i += 2) 4107 if (pts[i] == cp) break; 4108 if (i == c) { 4109 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4110 pts[c++] = cp; 4111 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4112 } 4113 } 4114 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4115 } 4116 } 4117 *numPoints = c / 2; 4118 *points = pts; 4119 PetscFunctionReturn(PETSC_SUCCESS); 4120 } 4121 4122 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4123 { 4124 DMPolytopeType ct; 4125 PetscInt *closure, *fifo; 4126 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4127 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4128 PetscInt depth, maxSize; 4129 4130 PetscFunctionBeginHot; 4131 PetscCall(DMPlexGetDepth(dm, &depth)); 4132 if (depth == 1) { 4133 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4134 PetscFunctionReturn(PETSC_SUCCESS); 4135 } 4136 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4137 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 4138 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4139 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4140 PetscFunctionReturn(PETSC_SUCCESS); 4141 } 4142 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4143 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4144 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4145 maxSize = PetscMax(coneSeries, supportSeries); 4146 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4147 if (*points) { 4148 closure = *points; 4149 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4150 closure[closureSize++] = p; 4151 closure[closureSize++] = ornt; 4152 fifo[fifoSize++] = p; 4153 fifo[fifoSize++] = ornt; 4154 fifo[fifoSize++] = ct; 4155 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4156 while (fifoSize - fifoStart) { 4157 const PetscInt q = fifo[fifoStart++]; 4158 const PetscInt o = fifo[fifoStart++]; 4159 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4160 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4161 const PetscInt *tmp, *tmpO = NULL; 4162 PetscInt tmpSize, t; 4163 4164 if (PetscDefined(USE_DEBUG)) { 4165 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4166 PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 4167 } 4168 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4169 for (t = 0; t < tmpSize; ++t) { 4170 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4171 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4172 const PetscInt cp = tmp[ip]; 4173 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4174 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4175 PetscInt c; 4176 4177 /* Check for duplicate */ 4178 for (c = 0; c < closureSize; c += 2) { 4179 if (closure[c] == cp) break; 4180 } 4181 if (c == closureSize) { 4182 closure[closureSize++] = cp; 4183 closure[closureSize++] = co; 4184 fifo[fifoSize++] = cp; 4185 fifo[fifoSize++] = co; 4186 fifo[fifoSize++] = ct; 4187 } 4188 } 4189 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4190 } 4191 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4192 if (numPoints) *numPoints = closureSize / 2; 4193 if (points) *points = closure; 4194 PetscFunctionReturn(PETSC_SUCCESS); 4195 } 4196 4197 /*@C 4198 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4199 4200 Not Collective 4201 4202 Input Parameters: 4203 + dm - The `DMPLEX` 4204 . p - The mesh point 4205 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4206 4207 Input/Output Parameter: 4208 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4209 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4210 otherwise the provided array is used to hold the values 4211 4212 Output Parameter: 4213 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4214 4215 Level: beginner 4216 4217 Note: 4218 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4219 4220 Fortran Notes: 4221 `points` must be declared with 4222 .vb 4223 PetscInt, pointer :: points(:) 4224 .ve 4225 and is always allocated by the function. 4226 4227 Pass `PETSC_NULL_INTEGER` for `numPoints` if it is not needed 4228 4229 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4230 @*/ 4231 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4232 { 4233 PetscFunctionBeginHot; 4234 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4235 if (numPoints) PetscAssertPointer(numPoints, 4); 4236 if (points) PetscAssertPointer(points, 5); 4237 if (PetscDefined(USE_DEBUG)) { 4238 PetscInt pStart, pEnd; 4239 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4240 PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 4241 } 4242 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4243 PetscFunctionReturn(PETSC_SUCCESS); 4244 } 4245 4246 /*@C 4247 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4248 4249 Not Collective 4250 4251 Input Parameters: 4252 + dm - The `DMPLEX` 4253 . p - The mesh point 4254 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4255 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4256 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4257 4258 Level: beginner 4259 4260 Note: 4261 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4262 4263 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4264 @*/ 4265 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4266 { 4267 PetscFunctionBeginHot; 4268 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4269 if (numPoints) *numPoints = 0; 4270 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4271 PetscFunctionReturn(PETSC_SUCCESS); 4272 } 4273 4274 /*@ 4275 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4276 4277 Not Collective 4278 4279 Input Parameter: 4280 . dm - The `DMPLEX` 4281 4282 Output Parameters: 4283 + maxConeSize - The maximum number of in-edges 4284 - maxSupportSize - The maximum number of out-edges 4285 4286 Level: beginner 4287 4288 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4289 @*/ 4290 PetscErrorCode DMPlexGetMaxSizes(DM dm, PeOp PetscInt *maxConeSize, PeOp PetscInt *maxSupportSize) 4291 { 4292 DM_Plex *mesh = (DM_Plex *)dm->data; 4293 4294 PetscFunctionBegin; 4295 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4296 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4297 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4298 PetscFunctionReturn(PETSC_SUCCESS); 4299 } 4300 4301 PetscErrorCode DMSetUp_Plex(DM dm) 4302 { 4303 DM_Plex *mesh = (DM_Plex *)dm->data; 4304 PetscInt size, maxSupportSize; 4305 4306 PetscFunctionBegin; 4307 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4308 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4309 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4310 PetscCall(PetscMalloc1(size, &mesh->cones)); 4311 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4312 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4313 if (maxSupportSize) { 4314 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4315 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4316 PetscCall(PetscMalloc1(size, &mesh->supports)); 4317 } 4318 PetscFunctionReturn(PETSC_SUCCESS); 4319 } 4320 4321 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4322 { 4323 PetscFunctionBegin; 4324 if (subdm) PetscCall(DMClone(dm, subdm)); 4325 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4326 if (subdm) (*subdm)->useNatural = dm->useNatural; 4327 if (dm->useNatural && dm->sfMigration) { 4328 PetscSF sfNatural; 4329 4330 (*subdm)->sfMigration = dm->sfMigration; 4331 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4332 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4333 (*subdm)->sfNatural = sfNatural; 4334 } 4335 PetscFunctionReturn(PETSC_SUCCESS); 4336 } 4337 4338 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4339 { 4340 PetscInt i = 0; 4341 4342 PetscFunctionBegin; 4343 PetscCall(DMClone(dms[0], superdm)); 4344 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4345 (*superdm)->useNatural = PETSC_FALSE; 4346 for (i = 0; i < len; i++) { 4347 if (dms[i]->useNatural && dms[i]->sfMigration) { 4348 PetscSF sfNatural; 4349 4350 (*superdm)->sfMigration = dms[i]->sfMigration; 4351 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4352 (*superdm)->useNatural = PETSC_TRUE; 4353 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4354 (*superdm)->sfNatural = sfNatural; 4355 break; 4356 } 4357 } 4358 PetscFunctionReturn(PETSC_SUCCESS); 4359 } 4360 4361 /*@ 4362 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4363 4364 Not Collective 4365 4366 Input Parameter: 4367 . dm - The `DMPLEX` 4368 4369 Level: beginner 4370 4371 Note: 4372 This should be called after all calls to `DMPlexSetCone()` 4373 4374 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4375 @*/ 4376 PetscErrorCode DMPlexSymmetrize(DM dm) 4377 { 4378 DM_Plex *mesh = (DM_Plex *)dm->data; 4379 PetscInt *offsets; 4380 PetscInt supportSize; 4381 PetscInt pStart, pEnd, p; 4382 4383 PetscFunctionBegin; 4384 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4385 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4386 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4387 /* Calculate support sizes */ 4388 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4389 for (p = pStart; p < pEnd; ++p) { 4390 PetscInt dof, off, c; 4391 4392 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4393 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4394 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4395 } 4396 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4397 /* Calculate supports */ 4398 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4399 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4400 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4401 for (p = pStart; p < pEnd; ++p) { 4402 PetscInt dof, off, c; 4403 4404 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4405 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4406 for (c = off; c < off + dof; ++c) { 4407 const PetscInt q = mesh->cones[c]; 4408 PetscInt offS; 4409 4410 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4411 4412 mesh->supports[offS + offsets[q]] = p; 4413 ++offsets[q]; 4414 } 4415 } 4416 PetscCall(PetscFree(offsets)); 4417 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4418 PetscFunctionReturn(PETSC_SUCCESS); 4419 } 4420 4421 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4422 { 4423 IS stratumIS; 4424 4425 PetscFunctionBegin; 4426 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4427 if (PetscDefined(USE_DEBUG)) { 4428 PetscInt qStart, qEnd, numLevels, level; 4429 PetscBool overlap = PETSC_FALSE; 4430 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4431 for (level = 0; level < numLevels; level++) { 4432 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4433 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4434 overlap = PETSC_TRUE; 4435 break; 4436 } 4437 } 4438 PetscCheck(!overlap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd); 4439 } 4440 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4441 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4442 PetscCall(ISDestroy(&stratumIS)); 4443 PetscFunctionReturn(PETSC_SUCCESS); 4444 } 4445 4446 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4447 { 4448 PetscInt *pMin, *pMax; 4449 PetscInt pStart, pEnd; 4450 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4451 4452 PetscFunctionBegin; 4453 { 4454 DMLabel label2; 4455 4456 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4457 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4458 } 4459 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4460 for (PetscInt p = pStart; p < pEnd; ++p) { 4461 DMPolytopeType ct; 4462 4463 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4464 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4465 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4466 } 4467 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4468 for (PetscInt d = dmin; d <= dmax; ++d) { 4469 pMin[d] = PETSC_INT_MAX; 4470 pMax[d] = PETSC_INT_MIN; 4471 } 4472 for (PetscInt p = pStart; p < pEnd; ++p) { 4473 DMPolytopeType ct; 4474 PetscInt d; 4475 4476 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4477 d = DMPolytopeTypeGetDim(ct); 4478 pMin[d] = PetscMin(p, pMin[d]); 4479 pMax[d] = PetscMax(p, pMax[d]); 4480 } 4481 for (PetscInt d = dmin; d <= dmax; ++d) { 4482 if (pMin[d] > pMax[d]) continue; 4483 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4484 } 4485 PetscCall(PetscFree2(pMin, pMax)); 4486 PetscFunctionReturn(PETSC_SUCCESS); 4487 } 4488 4489 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4490 { 4491 PetscInt pStart, pEnd; 4492 PetscInt numRoots = 0, numLeaves = 0; 4493 4494 PetscFunctionBegin; 4495 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4496 { 4497 /* Initialize roots and count leaves */ 4498 PetscInt sMin = PETSC_INT_MAX; 4499 PetscInt sMax = PETSC_INT_MIN; 4500 PetscInt coneSize, supportSize; 4501 4502 for (PetscInt p = pStart; p < pEnd; ++p) { 4503 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4504 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4505 if (!coneSize && supportSize) { 4506 sMin = PetscMin(p, sMin); 4507 sMax = PetscMax(p, sMax); 4508 ++numRoots; 4509 } else if (!supportSize && coneSize) { 4510 ++numLeaves; 4511 } else if (!supportSize && !coneSize) { 4512 /* Isolated points */ 4513 sMin = PetscMin(p, sMin); 4514 sMax = PetscMax(p, sMax); 4515 } 4516 } 4517 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4518 } 4519 4520 if (numRoots + numLeaves == (pEnd - pStart)) { 4521 PetscInt sMin = PETSC_INT_MAX; 4522 PetscInt sMax = PETSC_INT_MIN; 4523 PetscInt coneSize, supportSize; 4524 4525 for (PetscInt p = pStart; p < pEnd; ++p) { 4526 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4527 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4528 if (!supportSize && coneSize) { 4529 sMin = PetscMin(p, sMin); 4530 sMax = PetscMax(p, sMax); 4531 } 4532 } 4533 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4534 } else { 4535 PetscInt level = 0; 4536 PetscInt qStart, qEnd; 4537 4538 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4539 while (qEnd > qStart) { 4540 PetscInt sMin = PETSC_INT_MAX; 4541 PetscInt sMax = PETSC_INT_MIN; 4542 4543 for (PetscInt q = qStart; q < qEnd; ++q) { 4544 const PetscInt *support; 4545 PetscInt supportSize; 4546 4547 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4548 PetscCall(DMPlexGetSupport(dm, q, &support)); 4549 for (PetscInt s = 0; s < supportSize; ++s) { 4550 sMin = PetscMin(support[s], sMin); 4551 sMax = PetscMax(support[s], sMax); 4552 } 4553 } 4554 PetscCall(DMLabelGetNumValues(label, &level)); 4555 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4556 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4557 } 4558 } 4559 PetscFunctionReturn(PETSC_SUCCESS); 4560 } 4561 4562 /*@ 4563 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4564 4565 Collective 4566 4567 Input Parameter: 4568 . dm - The `DMPLEX` 4569 4570 Level: beginner 4571 4572 Notes: 4573 The strata group all points of the same grade, and this function calculates the strata. This 4574 grade can be seen as the height (or depth) of the point in the DAG. 4575 4576 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4577 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4578 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4579 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4580 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4581 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4582 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4583 4584 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4585 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4586 we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose 4587 to interpolate only that one (e0), so that 4588 .vb 4589 cone(c0) = {e0, v2} 4590 cone(e0) = {v0, v1} 4591 .ve 4592 If `DMPlexStratify()` is run on this mesh, it will give depths 4593 .vb 4594 depth 0 = {v0, v1, v2} 4595 depth 1 = {e0, c0} 4596 .ve 4597 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4598 4599 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4600 4601 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4602 @*/ 4603 PetscErrorCode DMPlexStratify(DM dm) 4604 { 4605 DM_Plex *mesh = (DM_Plex *)dm->data; 4606 DMLabel label; 4607 PetscBool flg = PETSC_FALSE; 4608 4609 PetscFunctionBegin; 4610 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4611 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4612 4613 // Create depth label 4614 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4615 PetscCall(DMCreateLabel(dm, "depth")); 4616 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4617 4618 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4619 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4620 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4621 4622 { /* just in case there is an empty process */ 4623 PetscInt numValues, maxValues = 0, v; 4624 4625 PetscCall(DMLabelGetNumValues(label, &numValues)); 4626 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4627 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4628 } 4629 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4630 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4631 PetscFunctionReturn(PETSC_SUCCESS); 4632 } 4633 4634 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4635 { 4636 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4637 PetscInt dim, depth, pheight, coneSize; 4638 PetscBool preferTensor; 4639 4640 PetscFunctionBeginHot; 4641 PetscCall(DMGetDimension(dm, &dim)); 4642 PetscCall(DMPlexGetDepth(dm, &depth)); 4643 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4644 PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor)); 4645 pheight = depth - pdepth; 4646 if (depth <= 1) { 4647 switch (pdepth) { 4648 case 0: 4649 ct = DM_POLYTOPE_POINT; 4650 break; 4651 case 1: 4652 switch (coneSize) { 4653 case 2: 4654 ct = DM_POLYTOPE_SEGMENT; 4655 break; 4656 case 3: 4657 ct = DM_POLYTOPE_TRIANGLE; 4658 break; 4659 case 4: 4660 switch (dim) { 4661 case 2: 4662 ct = DM_POLYTOPE_QUADRILATERAL; 4663 break; 4664 case 3: 4665 ct = DM_POLYTOPE_TETRAHEDRON; 4666 break; 4667 default: 4668 break; 4669 } 4670 break; 4671 case 5: 4672 ct = DM_POLYTOPE_PYRAMID; 4673 break; 4674 case 6: 4675 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4676 break; 4677 case 8: 4678 ct = DM_POLYTOPE_HEXAHEDRON; 4679 break; 4680 default: 4681 break; 4682 } 4683 } 4684 } else { 4685 if (pdepth == 0) { 4686 ct = DM_POLYTOPE_POINT; 4687 } else if (pheight == 0) { 4688 switch (dim) { 4689 case 1: 4690 switch (coneSize) { 4691 case 2: 4692 ct = DM_POLYTOPE_SEGMENT; 4693 break; 4694 default: 4695 break; 4696 } 4697 break; 4698 case 2: 4699 switch (coneSize) { 4700 case 3: 4701 ct = DM_POLYTOPE_TRIANGLE; 4702 break; 4703 case 4: 4704 ct = DM_POLYTOPE_QUADRILATERAL; 4705 break; 4706 default: 4707 break; 4708 } 4709 break; 4710 case 3: 4711 switch (coneSize) { 4712 case 4: 4713 ct = DM_POLYTOPE_TETRAHEDRON; 4714 break; 4715 case 5: { 4716 const PetscInt *cone; 4717 PetscInt faceConeSize; 4718 4719 PetscCall(DMPlexGetCone(dm, p, &cone)); 4720 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4721 switch (faceConeSize) { 4722 case 3: 4723 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4724 break; 4725 case 4: 4726 ct = DM_POLYTOPE_PYRAMID; 4727 break; 4728 } 4729 } break; 4730 case 6: 4731 ct = DM_POLYTOPE_HEXAHEDRON; 4732 break; 4733 default: 4734 break; 4735 } 4736 break; 4737 default: 4738 break; 4739 } 4740 } else if (pheight > 0) { 4741 switch (coneSize) { 4742 case 2: 4743 ct = DM_POLYTOPE_SEGMENT; 4744 break; 4745 case 3: 4746 ct = DM_POLYTOPE_TRIANGLE; 4747 break; 4748 case 4: 4749 ct = DM_POLYTOPE_QUADRILATERAL; 4750 break; 4751 default: 4752 break; 4753 } 4754 } 4755 } 4756 *pt = ct; 4757 PetscFunctionReturn(PETSC_SUCCESS); 4758 } 4759 4760 /*@ 4761 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4762 4763 Collective 4764 4765 Input Parameter: 4766 . dm - The `DMPLEX` 4767 4768 Level: developer 4769 4770 Note: 4771 This function is normally called automatically when a cell type is requested. It creates an 4772 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4773 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4774 4775 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4776 4777 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4778 @*/ 4779 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4780 { 4781 DM_Plex *mesh; 4782 DMLabel ctLabel; 4783 PetscInt pStart, pEnd, p; 4784 4785 PetscFunctionBegin; 4786 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4787 mesh = (DM_Plex *)dm->data; 4788 PetscCall(DMCreateLabel(dm, "celltype")); 4789 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4790 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4791 PetscCall(PetscFree(mesh->cellTypes)); 4792 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4793 for (p = pStart; p < pEnd; ++p) { 4794 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4795 PetscInt pdepth; 4796 4797 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4798 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4799 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]); 4800 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4801 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4802 } 4803 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4804 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4805 PetscFunctionReturn(PETSC_SUCCESS); 4806 } 4807 4808 /*@C 4809 DMPlexGetJoin - Get an array for the join of the set of points 4810 4811 Not Collective 4812 4813 Input Parameters: 4814 + dm - The `DMPLEX` object 4815 . numPoints - The number of input points for the join 4816 - points - The input points 4817 4818 Output Parameters: 4819 + numCoveredPoints - The number of points in the join 4820 - coveredPoints - The points in the join 4821 4822 Level: intermediate 4823 4824 Note: 4825 Currently, this is restricted to a single level join 4826 4827 Fortran Notes: 4828 `converedPoints` must be declared with 4829 .vb 4830 PetscInt, pointer :: coveredPints(:) 4831 .ve 4832 4833 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4834 @*/ 4835 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4836 { 4837 DM_Plex *mesh = (DM_Plex *)dm->data; 4838 PetscInt *join[2]; 4839 PetscInt joinSize, i = 0; 4840 PetscInt dof, off, p, c, m; 4841 PetscInt maxSupportSize; 4842 4843 PetscFunctionBegin; 4844 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4845 PetscAssertPointer(points, 3); 4846 PetscAssertPointer(numCoveredPoints, 4); 4847 PetscAssertPointer(coveredPoints, 5); 4848 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4849 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4850 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4851 /* Copy in support of first point */ 4852 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4853 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4854 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4855 /* Check each successive support */ 4856 for (p = 1; p < numPoints; ++p) { 4857 PetscInt newJoinSize = 0; 4858 4859 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4860 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4861 for (c = 0; c < dof; ++c) { 4862 const PetscInt point = mesh->supports[off + c]; 4863 4864 for (m = 0; m < joinSize; ++m) { 4865 if (point == join[i][m]) { 4866 join[1 - i][newJoinSize++] = point; 4867 break; 4868 } 4869 } 4870 } 4871 joinSize = newJoinSize; 4872 i = 1 - i; 4873 } 4874 *numCoveredPoints = joinSize; 4875 *coveredPoints = join[i]; 4876 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4877 PetscFunctionReturn(PETSC_SUCCESS); 4878 } 4879 4880 /*@C 4881 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4882 4883 Not Collective 4884 4885 Input Parameters: 4886 + dm - The `DMPLEX` object 4887 . numPoints - The number of input points for the join 4888 - points - The input points 4889 4890 Output Parameters: 4891 + numCoveredPoints - The number of points in the join 4892 - coveredPoints - The points in the join 4893 4894 Level: intermediate 4895 4896 Fortran Notes: 4897 `converedPoints` must be declared with 4898 .vb 4899 PetscInt, pointer :: coveredPoints(:) 4900 .ve 4901 4902 Pass `PETSC_NULL_INTEGER` for `numCoveredPoints` if it is not needed 4903 4904 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4905 @*/ 4906 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4907 { 4908 PetscFunctionBegin; 4909 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4910 if (points) PetscAssertPointer(points, 3); 4911 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4912 PetscAssertPointer(coveredPoints, 5); 4913 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4914 if (numCoveredPoints) *numCoveredPoints = 0; 4915 PetscFunctionReturn(PETSC_SUCCESS); 4916 } 4917 4918 /*@C 4919 DMPlexGetFullJoin - Get an array for the join of the set of points 4920 4921 Not Collective 4922 4923 Input Parameters: 4924 + dm - The `DMPLEX` object 4925 . numPoints - The number of input points for the join 4926 - points - The input points, its length is `numPoints` 4927 4928 Output Parameters: 4929 + numCoveredPoints - The number of points in the join 4930 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4931 4932 Level: intermediate 4933 4934 Fortran Notes: 4935 .vb 4936 PetscInt, pointer :: coveredPints(:) 4937 .ve 4938 4939 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4940 @*/ 4941 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4942 { 4943 PetscInt *offsets, **closures; 4944 PetscInt *join[2]; 4945 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4946 PetscInt p, d, c, m, ms; 4947 4948 PetscFunctionBegin; 4949 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4950 PetscAssertPointer(points, 3); 4951 PetscAssertPointer(numCoveredPoints, 4); 4952 PetscAssertPointer(coveredPoints, 5); 4953 4954 PetscCall(DMPlexGetDepth(dm, &depth)); 4955 PetscCall(PetscCalloc1(numPoints, &closures)); 4956 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4957 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4958 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4959 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4960 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4961 4962 for (p = 0; p < numPoints; ++p) { 4963 PetscInt closureSize; 4964 4965 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4966 4967 offsets[p * (depth + 2) + 0] = 0; 4968 for (d = 0; d < depth + 1; ++d) { 4969 PetscInt pStart, pEnd, i; 4970 4971 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4972 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4973 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4974 offsets[p * (depth + 2) + d + 1] = i; 4975 break; 4976 } 4977 } 4978 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4979 } 4980 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); 4981 } 4982 for (d = 0; d < depth + 1; ++d) { 4983 PetscInt dof; 4984 4985 /* Copy in support of first point */ 4986 dof = offsets[d + 1] - offsets[d]; 4987 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4988 /* Check each successive cone */ 4989 for (p = 1; p < numPoints && joinSize; ++p) { 4990 PetscInt newJoinSize = 0; 4991 4992 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4993 for (c = 0; c < dof; ++c) { 4994 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4995 4996 for (m = 0; m < joinSize; ++m) { 4997 if (point == join[i][m]) { 4998 join[1 - i][newJoinSize++] = point; 4999 break; 5000 } 5001 } 5002 } 5003 joinSize = newJoinSize; 5004 i = 1 - i; 5005 } 5006 if (joinSize) break; 5007 } 5008 *numCoveredPoints = joinSize; 5009 *coveredPoints = join[i]; 5010 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 5011 PetscCall(PetscFree(closures)); 5012 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 5013 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 5014 PetscFunctionReturn(PETSC_SUCCESS); 5015 } 5016 5017 /*@C 5018 DMPlexGetMeet - Get an array for the meet of the set of points 5019 5020 Not Collective 5021 5022 Input Parameters: 5023 + dm - The `DMPLEX` object 5024 . numPoints - The number of input points for the meet 5025 - points - The input points, of length `numPoints` 5026 5027 Output Parameters: 5028 + numCoveringPoints - The number of points in the meet 5029 - coveringPoints - The points in the meet, of length `numCoveringPoints` 5030 5031 Level: intermediate 5032 5033 Note: 5034 Currently, this is restricted to a single level meet 5035 5036 Fortran Note: 5037 `coveringPoints` must be declared with 5038 .vb 5039 PetscInt, pointer :: coveringPoints(:) 5040 .ve 5041 5042 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5043 @*/ 5044 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 5045 { 5046 DM_Plex *mesh = (DM_Plex *)dm->data; 5047 PetscInt *meet[2]; 5048 PetscInt meetSize, i = 0; 5049 PetscInt dof, off, p, c, m; 5050 PetscInt maxConeSize; 5051 5052 PetscFunctionBegin; 5053 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5054 PetscAssertPointer(points, 3); 5055 PetscAssertPointer(numCoveringPoints, 4); 5056 PetscAssertPointer(coveringPoints, 5); 5057 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 5058 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 5059 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 5060 /* Copy in cone of first point */ 5061 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 5062 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 5063 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5064 /* Check each successive cone */ 5065 for (p = 1; p < numPoints; ++p) { 5066 PetscInt newMeetSize = 0; 5067 5068 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5069 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5070 for (c = 0; c < dof; ++c) { 5071 const PetscInt point = mesh->cones[off + c]; 5072 5073 for (m = 0; m < meetSize; ++m) { 5074 if (point == meet[i][m]) { 5075 meet[1 - i][newMeetSize++] = point; 5076 break; 5077 } 5078 } 5079 } 5080 meetSize = newMeetSize; 5081 i = 1 - i; 5082 } 5083 *numCoveringPoints = meetSize; 5084 *coveringPoints = meet[i]; 5085 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5086 PetscFunctionReturn(PETSC_SUCCESS); 5087 } 5088 5089 /*@C 5090 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5091 5092 Not Collective 5093 5094 Input Parameters: 5095 + dm - The `DMPLEX` object 5096 . numPoints - The number of input points for the meet 5097 - points - The input points 5098 5099 Output Parameters: 5100 + numCoveredPoints - The number of points in the meet 5101 - coveredPoints - The points in the meet 5102 5103 Level: intermediate 5104 5105 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5106 @*/ 5107 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5108 { 5109 PetscFunctionBegin; 5110 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5111 if (points) PetscAssertPointer(points, 3); 5112 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5113 PetscAssertPointer(coveredPoints, 5); 5114 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5115 if (numCoveredPoints) *numCoveredPoints = 0; 5116 PetscFunctionReturn(PETSC_SUCCESS); 5117 } 5118 5119 /*@C 5120 DMPlexGetFullMeet - Get an array for the meet of the set of points 5121 5122 Not Collective 5123 5124 Input Parameters: 5125 + dm - The `DMPLEX` object 5126 . numPoints - The number of input points for the meet 5127 - points - The input points, of length `numPoints` 5128 5129 Output Parameters: 5130 + numCoveredPoints - The number of points in the meet 5131 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5132 5133 Level: intermediate 5134 5135 Fortran Notes: 5136 `coveredPoints` must be declared with 5137 .vb 5138 PetscInt, pointer :: coveredPoints(:) 5139 .ve 5140 5141 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5142 @*/ 5143 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5144 { 5145 PetscInt *offsets, **closures; 5146 PetscInt *meet[2]; 5147 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5148 PetscInt p, h, c, m, mc; 5149 5150 PetscFunctionBegin; 5151 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5152 PetscAssertPointer(points, 3); 5153 PetscAssertPointer(numCoveredPoints, 4); 5154 PetscAssertPointer(coveredPoints, 5); 5155 5156 PetscCall(DMPlexGetDepth(dm, &height)); 5157 PetscCall(PetscMalloc1(numPoints, &closures)); 5158 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5159 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5160 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5161 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5162 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5163 5164 for (p = 0; p < numPoints; ++p) { 5165 PetscInt closureSize; 5166 5167 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5168 5169 offsets[p * (height + 2) + 0] = 0; 5170 for (h = 0; h < height + 1; ++h) { 5171 PetscInt pStart, pEnd, i; 5172 5173 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5174 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5175 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5176 offsets[p * (height + 2) + h + 1] = i; 5177 break; 5178 } 5179 } 5180 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5181 } 5182 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); 5183 } 5184 for (h = 0; h < height + 1; ++h) { 5185 PetscInt dof; 5186 5187 /* Copy in cone of first point */ 5188 dof = offsets[h + 1] - offsets[h]; 5189 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5190 /* Check each successive cone */ 5191 for (p = 1; p < numPoints && meetSize; ++p) { 5192 PetscInt newMeetSize = 0; 5193 5194 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5195 for (c = 0; c < dof; ++c) { 5196 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5197 5198 for (m = 0; m < meetSize; ++m) { 5199 if (point == meet[i][m]) { 5200 meet[1 - i][newMeetSize++] = point; 5201 break; 5202 } 5203 } 5204 } 5205 meetSize = newMeetSize; 5206 i = 1 - i; 5207 } 5208 if (meetSize) break; 5209 } 5210 *numCoveredPoints = meetSize; 5211 *coveredPoints = meet[i]; 5212 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5213 PetscCall(PetscFree(closures)); 5214 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5215 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5216 PetscFunctionReturn(PETSC_SUCCESS); 5217 } 5218 5219 /*@ 5220 DMPlexEqual - Determine if two `DM` have the same topology 5221 5222 Not Collective 5223 5224 Input Parameters: 5225 + dmA - A `DMPLEX` object 5226 - dmB - A `DMPLEX` object 5227 5228 Output Parameter: 5229 . equal - `PETSC_TRUE` if the topologies are identical 5230 5231 Level: intermediate 5232 5233 Note: 5234 We are not solving graph isomorphism, so we do not permute. 5235 5236 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5237 @*/ 5238 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5239 { 5240 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5241 5242 PetscFunctionBegin; 5243 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5244 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5245 PetscAssertPointer(equal, 3); 5246 5247 *equal = PETSC_FALSE; 5248 PetscCall(DMPlexGetDepth(dmA, &depth)); 5249 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5250 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5251 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5252 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5253 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5254 for (p = pStart; p < pEnd; ++p) { 5255 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5256 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5257 5258 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5259 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5260 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5261 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5262 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5263 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5264 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5265 for (c = 0; c < coneSize; ++c) { 5266 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5267 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5268 } 5269 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5270 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5271 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5272 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5273 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5274 for (s = 0; s < supportSize; ++s) { 5275 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5276 } 5277 } 5278 *equal = PETSC_TRUE; 5279 PetscFunctionReturn(PETSC_SUCCESS); 5280 } 5281 5282 /*@ 5283 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5284 5285 Not Collective 5286 5287 Input Parameters: 5288 + dm - The `DMPLEX` 5289 . cellDim - The cell dimension 5290 - numCorners - The number of vertices on a cell 5291 5292 Output Parameter: 5293 . numFaceVertices - The number of vertices on a face 5294 5295 Level: developer 5296 5297 Note: 5298 Of course this can only work for a restricted set of symmetric shapes 5299 5300 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5301 @*/ 5302 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5303 { 5304 MPI_Comm comm; 5305 5306 PetscFunctionBegin; 5307 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5308 PetscAssertPointer(numFaceVertices, 4); 5309 switch (cellDim) { 5310 case 0: 5311 *numFaceVertices = 0; 5312 break; 5313 case 1: 5314 *numFaceVertices = 1; 5315 break; 5316 case 2: 5317 switch (numCorners) { 5318 case 3: /* triangle */ 5319 *numFaceVertices = 2; /* Edge has 2 vertices */ 5320 break; 5321 case 4: /* quadrilateral */ 5322 *numFaceVertices = 2; /* Edge has 2 vertices */ 5323 break; 5324 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5325 *numFaceVertices = 3; /* Edge has 3 vertices */ 5326 break; 5327 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5328 *numFaceVertices = 3; /* Edge has 3 vertices */ 5329 break; 5330 default: 5331 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5332 } 5333 break; 5334 case 3: 5335 switch (numCorners) { 5336 case 4: /* tetradehdron */ 5337 *numFaceVertices = 3; /* Face has 3 vertices */ 5338 break; 5339 case 6: /* tet cohesive cells */ 5340 *numFaceVertices = 4; /* Face has 4 vertices */ 5341 break; 5342 case 8: /* hexahedron */ 5343 *numFaceVertices = 4; /* Face has 4 vertices */ 5344 break; 5345 case 9: /* tet cohesive Lagrange cells */ 5346 *numFaceVertices = 6; /* Face has 6 vertices */ 5347 break; 5348 case 10: /* quadratic tetrahedron */ 5349 *numFaceVertices = 6; /* Face has 6 vertices */ 5350 break; 5351 case 12: /* hex cohesive Lagrange cells */ 5352 *numFaceVertices = 6; /* Face has 6 vertices */ 5353 break; 5354 case 18: /* quadratic tet cohesive Lagrange cells */ 5355 *numFaceVertices = 6; /* Face has 6 vertices */ 5356 break; 5357 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5358 *numFaceVertices = 9; /* Face has 9 vertices */ 5359 break; 5360 default: 5361 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5362 } 5363 break; 5364 default: 5365 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5366 } 5367 PetscFunctionReturn(PETSC_SUCCESS); 5368 } 5369 5370 /*@ 5371 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5372 5373 Not Collective 5374 5375 Input Parameter: 5376 . dm - The `DMPLEX` object 5377 5378 Output Parameter: 5379 . depthLabel - The `DMLabel` recording point depth 5380 5381 Level: developer 5382 5383 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5384 @*/ 5385 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5386 { 5387 PetscFunctionBegin; 5388 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5389 PetscAssertPointer(depthLabel, 2); 5390 *depthLabel = dm->depthLabel; 5391 PetscFunctionReturn(PETSC_SUCCESS); 5392 } 5393 5394 /*@ 5395 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5396 5397 Not Collective 5398 5399 Input Parameter: 5400 . dm - The `DMPLEX` object 5401 5402 Output Parameter: 5403 . depth - The number of strata (breadth first levels) in the DAG 5404 5405 Level: developer 5406 5407 Notes: 5408 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5409 5410 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5411 5412 An empty mesh gives -1. 5413 5414 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5415 @*/ 5416 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5417 { 5418 DM_Plex *mesh = (DM_Plex *)dm->data; 5419 DMLabel label; 5420 PetscInt d = -1; 5421 5422 PetscFunctionBegin; 5423 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5424 PetscAssertPointer(depth, 2); 5425 if (mesh->tr) { 5426 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5427 } else { 5428 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5429 // Allow missing depths 5430 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5431 *depth = d; 5432 } 5433 PetscFunctionReturn(PETSC_SUCCESS); 5434 } 5435 5436 /*@ 5437 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5438 5439 Not Collective 5440 5441 Input Parameters: 5442 + dm - The `DMPLEX` object 5443 - depth - The requested depth 5444 5445 Output Parameters: 5446 + start - The first point at this `depth` 5447 - end - One beyond the last point at this `depth` 5448 5449 Level: developer 5450 5451 Notes: 5452 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5453 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5454 higher dimension, e.g., "edges". 5455 5456 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5457 @*/ 5458 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PeOp PetscInt *start, PeOp PetscInt *end) 5459 { 5460 DM_Plex *mesh = (DM_Plex *)dm->data; 5461 DMLabel label; 5462 PetscInt pStart, pEnd; 5463 5464 PetscFunctionBegin; 5465 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5466 if (start) { 5467 PetscAssertPointer(start, 3); 5468 *start = 0; 5469 } 5470 if (end) { 5471 PetscAssertPointer(end, 4); 5472 *end = 0; 5473 } 5474 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5475 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5476 if (depth < 0) { 5477 if (start) *start = pStart; 5478 if (end) *end = pEnd; 5479 PetscFunctionReturn(PETSC_SUCCESS); 5480 } 5481 if (mesh->tr) { 5482 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5483 } else { 5484 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5485 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5486 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5487 } 5488 PetscFunctionReturn(PETSC_SUCCESS); 5489 } 5490 5491 /*@ 5492 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5493 5494 Not Collective 5495 5496 Input Parameters: 5497 + dm - The `DMPLEX` object 5498 - height - The requested height 5499 5500 Output Parameters: 5501 + start - The first point at this `height` 5502 - end - One beyond the last point at this `height` 5503 5504 Level: developer 5505 5506 Notes: 5507 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5508 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5509 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5510 5511 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5512 @*/ 5513 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PeOp PetscInt *start, PeOp PetscInt *end) 5514 { 5515 DMLabel label; 5516 PetscInt depth, pStart, pEnd; 5517 5518 PetscFunctionBegin; 5519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5520 if (start) { 5521 PetscAssertPointer(start, 3); 5522 *start = 0; 5523 } 5524 if (end) { 5525 PetscAssertPointer(end, 4); 5526 *end = 0; 5527 } 5528 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5529 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5530 if (height < 0) { 5531 if (start) *start = pStart; 5532 if (end) *end = pEnd; 5533 PetscFunctionReturn(PETSC_SUCCESS); 5534 } 5535 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5536 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5537 else PetscCall(DMGetDimension(dm, &depth)); 5538 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5539 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5540 PetscFunctionReturn(PETSC_SUCCESS); 5541 } 5542 5543 /*@ 5544 DMPlexGetPointDepth - Get the `depth` of a given point 5545 5546 Not Collective 5547 5548 Input Parameters: 5549 + dm - The `DMPLEX` object 5550 - point - The point 5551 5552 Output Parameter: 5553 . depth - The depth of the `point` 5554 5555 Level: intermediate 5556 5557 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5558 @*/ 5559 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5560 { 5561 PetscFunctionBegin; 5562 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5563 PetscAssertPointer(depth, 3); 5564 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5565 PetscFunctionReturn(PETSC_SUCCESS); 5566 } 5567 5568 /*@ 5569 DMPlexGetPointHeight - Get the `height` of a given point 5570 5571 Not Collective 5572 5573 Input Parameters: 5574 + dm - The `DMPLEX` object 5575 - point - The point 5576 5577 Output Parameter: 5578 . height - The height of the `point` 5579 5580 Level: intermediate 5581 5582 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5583 @*/ 5584 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5585 { 5586 PetscInt n, pDepth; 5587 5588 PetscFunctionBegin; 5589 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5590 PetscAssertPointer(height, 3); 5591 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5592 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5593 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5594 PetscFunctionReturn(PETSC_SUCCESS); 5595 } 5596 5597 /*@ 5598 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5599 5600 Not Collective 5601 5602 Input Parameter: 5603 . dm - The `DMPLEX` object 5604 5605 Output Parameter: 5606 . celltypeLabel - The `DMLabel` recording cell polytope type 5607 5608 Level: developer 5609 5610 Note: 5611 This function will trigger automatica computation of cell types. This can be disabled by calling 5612 `DMCreateLabel`(dm, "celltype") beforehand. 5613 5614 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5615 @*/ 5616 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5617 { 5618 PetscFunctionBegin; 5619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5620 PetscAssertPointer(celltypeLabel, 2); 5621 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5622 *celltypeLabel = dm->celltypeLabel; 5623 PetscFunctionReturn(PETSC_SUCCESS); 5624 } 5625 5626 /*@ 5627 DMPlexGetCellType - Get the polytope type of a given cell 5628 5629 Not Collective 5630 5631 Input Parameters: 5632 + dm - The `DMPLEX` object 5633 - cell - The cell 5634 5635 Output Parameter: 5636 . celltype - The polytope type of the cell 5637 5638 Level: intermediate 5639 5640 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5641 @*/ 5642 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5643 { 5644 DM_Plex *mesh = (DM_Plex *)dm->data; 5645 DMLabel label; 5646 PetscInt ct; 5647 5648 PetscFunctionBegin; 5649 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5650 PetscAssertPointer(celltype, 3); 5651 if (mesh->tr) { 5652 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5653 } else { 5654 PetscInt pStart, pEnd; 5655 5656 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5657 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5658 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5659 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5660 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5661 for (PetscInt p = pStart; p < pEnd; p++) { 5662 PetscCall(DMLabelGetValue(label, p, &ct)); 5663 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5664 } 5665 } 5666 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5667 if (PetscDefined(USE_DEBUG)) { 5668 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5669 PetscCall(DMLabelGetValue(label, cell, &ct)); 5670 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5671 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5672 } 5673 } 5674 PetscFunctionReturn(PETSC_SUCCESS); 5675 } 5676 5677 /*@ 5678 DMPlexSetCellType - Set the polytope type of a given cell 5679 5680 Not Collective 5681 5682 Input Parameters: 5683 + dm - The `DMPLEX` object 5684 . cell - The cell 5685 - celltype - The polytope type of the cell 5686 5687 Level: advanced 5688 5689 Note: 5690 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5691 is executed. This function will override the computed type. However, if automatic classification will not succeed 5692 and a user wants to manually specify all types, the classification must be disabled by calling 5693 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5694 5695 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5696 @*/ 5697 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5698 { 5699 DM_Plex *mesh = (DM_Plex *)dm->data; 5700 DMLabel label; 5701 PetscInt pStart, pEnd; 5702 5703 PetscFunctionBegin; 5704 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5705 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5706 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5707 PetscCall(DMLabelSetValue(label, cell, celltype)); 5708 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5709 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5710 PetscFunctionReturn(PETSC_SUCCESS); 5711 } 5712 5713 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5714 { 5715 PetscSection section; 5716 PetscInt maxHeight; 5717 const char *prefix; 5718 5719 PetscFunctionBegin; 5720 PetscCall(DMClone(dm, cdm)); 5721 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5722 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5723 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5724 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5725 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5726 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5727 PetscCall(DMSetLocalSection(*cdm, section)); 5728 PetscCall(PetscSectionDestroy(§ion)); 5729 5730 PetscCall(DMSetNumFields(*cdm, 1)); 5731 PetscCall(DMCreateDS(*cdm)); 5732 (*cdm)->cloneOpts = PETSC_TRUE; 5733 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5734 PetscFunctionReturn(PETSC_SUCCESS); 5735 } 5736 5737 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5738 { 5739 Vec coordsLocal, cellCoordsLocal; 5740 DM coordsDM, cellCoordsDM; 5741 5742 PetscFunctionBegin; 5743 *field = NULL; 5744 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5745 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5746 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5747 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5748 if (coordsLocal && coordsDM) { 5749 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5750 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5751 } 5752 PetscFunctionReturn(PETSC_SUCCESS); 5753 } 5754 5755 /*@ 5756 DMPlexGetConeSection - Return a section which describes the layout of cone data 5757 5758 Not Collective 5759 5760 Input Parameter: 5761 . dm - The `DMPLEX` object 5762 5763 Output Parameter: 5764 . section - The `PetscSection` object 5765 5766 Level: developer 5767 5768 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5769 @*/ 5770 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5771 { 5772 DM_Plex *mesh = (DM_Plex *)dm->data; 5773 5774 PetscFunctionBegin; 5775 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5776 if (section) *section = mesh->coneSection; 5777 PetscFunctionReturn(PETSC_SUCCESS); 5778 } 5779 5780 /*@ 5781 DMPlexGetSupportSection - Return a section which describes the layout of support data 5782 5783 Not Collective 5784 5785 Input Parameter: 5786 . dm - The `DMPLEX` object 5787 5788 Output Parameter: 5789 . section - The `PetscSection` object 5790 5791 Level: developer 5792 5793 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5794 @*/ 5795 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5796 { 5797 DM_Plex *mesh = (DM_Plex *)dm->data; 5798 5799 PetscFunctionBegin; 5800 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5801 if (section) *section = mesh->supportSection; 5802 PetscFunctionReturn(PETSC_SUCCESS); 5803 } 5804 5805 /*@C 5806 DMPlexGetCones - Return cone data 5807 5808 Not Collective 5809 5810 Input Parameter: 5811 . dm - The `DMPLEX` object 5812 5813 Output Parameter: 5814 . cones - The cone for each point 5815 5816 Level: developer 5817 5818 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5819 @*/ 5820 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5821 { 5822 DM_Plex *mesh = (DM_Plex *)dm->data; 5823 5824 PetscFunctionBegin; 5825 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5826 if (cones) *cones = mesh->cones; 5827 PetscFunctionReturn(PETSC_SUCCESS); 5828 } 5829 5830 /*@C 5831 DMPlexGetConeOrientations - Return cone orientation data 5832 5833 Not Collective 5834 5835 Input Parameter: 5836 . dm - The `DMPLEX` object 5837 5838 Output Parameter: 5839 . coneOrientations - The array of cone orientations for all points 5840 5841 Level: developer 5842 5843 Notes: 5844 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5845 as returned by `DMPlexGetConeOrientation()`. 5846 5847 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5848 5849 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5850 @*/ 5851 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5852 { 5853 DM_Plex *mesh = (DM_Plex *)dm->data; 5854 5855 PetscFunctionBegin; 5856 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5857 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5858 PetscFunctionReturn(PETSC_SUCCESS); 5859 } 5860 5861 /* FEM Support */ 5862 5863 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5864 { 5865 PetscInt depth; 5866 5867 PetscFunctionBegin; 5868 PetscCall(DMPlexGetDepth(plex, &depth)); 5869 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5870 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5871 PetscFunctionReturn(PETSC_SUCCESS); 5872 } 5873 5874 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5875 { 5876 PetscInt depth; 5877 5878 PetscFunctionBegin; 5879 PetscCall(DMPlexGetDepth(plex, &depth)); 5880 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5881 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5882 PetscFunctionReturn(PETSC_SUCCESS); 5883 } 5884 5885 /* 5886 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5887 representing a line in the section. 5888 */ 5889 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5890 { 5891 PetscObject obj; 5892 PetscClassId id; 5893 PetscFE fe = NULL; 5894 5895 PetscFunctionBeginHot; 5896 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5897 PetscCall(DMGetField(dm, field, NULL, &obj)); 5898 PetscCall(PetscObjectGetClassId(obj, &id)); 5899 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5900 5901 if (!fe) { 5902 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5903 /* An order k SEM disc has k-1 dofs on an edge */ 5904 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5905 *k = *k / *Nc + 1; 5906 } else { 5907 PetscInt dual_space_size, dim; 5908 PetscDualSpace dsp; 5909 5910 PetscCall(DMGetDimension(dm, &dim)); 5911 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5912 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5913 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5914 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5915 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5916 } 5917 PetscFunctionReturn(PETSC_SUCCESS); 5918 } 5919 5920 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5921 { 5922 PetscFunctionBeginHot; 5923 if (tensor) { 5924 *dof = PetscPowInt(k + 1, dim); 5925 } else { 5926 switch (dim) { 5927 case 1: 5928 *dof = k + 1; 5929 break; 5930 case 2: 5931 *dof = ((k + 1) * (k + 2)) / 2; 5932 break; 5933 case 3: 5934 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5935 break; 5936 default: 5937 *dof = 0; 5938 } 5939 } 5940 PetscFunctionReturn(PETSC_SUCCESS); 5941 } 5942 5943 /*@ 5944 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5945 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5946 section provided (or the section of the `DM`). 5947 5948 Input Parameters: 5949 + dm - The `DM` 5950 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5951 - section - The `PetscSection` to reorder, or `NULL` for the default section 5952 5953 Example: 5954 A typical interpolated single-quad mesh might order points as 5955 .vb 5956 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5957 5958 v4 -- e6 -- v3 5959 | | 5960 e7 c0 e8 5961 | | 5962 v1 -- e5 -- v2 5963 .ve 5964 5965 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5966 dofs in the order of points, e.g., 5967 .vb 5968 c0 -> [0,1,2,3] 5969 v1 -> [4] 5970 ... 5971 e5 -> [8, 9] 5972 .ve 5973 5974 which corresponds to the dofs 5975 .vb 5976 6 10 11 7 5977 13 2 3 15 5978 12 0 1 14 5979 4 8 9 5 5980 .ve 5981 5982 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5983 .vb 5984 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5985 .ve 5986 5987 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5988 .vb 5989 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5990 .ve 5991 5992 Level: developer 5993 5994 Notes: 5995 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5996 degree of the basis. 5997 5998 This is required to run with libCEED. 5999 6000 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 6001 @*/ 6002 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 6003 { 6004 DMLabel label; 6005 PetscInt dim, depth = -1, eStart = -1, Nf; 6006 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 6007 6008 PetscFunctionBegin; 6009 PetscCall(DMGetDimension(dm, &dim)); 6010 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 6011 if (point < 0) { 6012 PetscInt sStart, sEnd; 6013 6014 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6015 point = sEnd - sStart ? sStart : point; 6016 } 6017 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6018 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6019 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6020 if (depth == 1) { 6021 eStart = point; 6022 } else if (depth == dim) { 6023 const PetscInt *cone; 6024 6025 PetscCall(DMPlexGetCone(dm, point, &cone)); 6026 if (dim == 2) eStart = cone[0]; 6027 else if (dim == 3) { 6028 const PetscInt *cone2; 6029 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6030 eStart = cone2[0]; 6031 } 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); 6032 } 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); 6033 6034 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6035 for (PetscInt d = 1; d <= dim; d++) { 6036 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6037 PetscInt *perm; 6038 6039 for (f = 0; f < Nf; ++f) { 6040 PetscInt dof; 6041 6042 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6043 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6044 if (!continuous && d < dim) continue; 6045 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6046 size += dof * Nc; 6047 } 6048 PetscCall(PetscMalloc1(size, &perm)); 6049 for (f = 0; f < Nf; ++f) { 6050 switch (d) { 6051 case 1: 6052 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6053 if (!continuous && d < dim) continue; 6054 /* 6055 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6056 We want [ vtx0; edge of length k-1; vtx1 ] 6057 */ 6058 if (continuous) { 6059 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6060 for (i = 0; i < k - 1; i++) 6061 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6062 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6063 foffset = offset; 6064 } else { 6065 PetscInt dof; 6066 6067 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6068 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6069 foffset = offset; 6070 } 6071 break; 6072 case 2: 6073 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6074 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6075 if (!continuous && d < dim) continue; 6076 /* The SEM order is 6077 6078 v_lb, {e_b}, v_rb, 6079 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6080 v_lt, reverse {e_t}, v_rt 6081 */ 6082 if (continuous) { 6083 const PetscInt of = 0; 6084 const PetscInt oeb = of + PetscSqr(k - 1); 6085 const PetscInt oer = oeb + (k - 1); 6086 const PetscInt oet = oer + (k - 1); 6087 const PetscInt oel = oet + (k - 1); 6088 const PetscInt ovlb = oel + (k - 1); 6089 const PetscInt ovrb = ovlb + 1; 6090 const PetscInt ovrt = ovrb + 1; 6091 const PetscInt ovlt = ovrt + 1; 6092 PetscInt o; 6093 6094 /* bottom */ 6095 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6096 for (o = oeb; o < oer; ++o) 6097 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6098 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6099 /* middle */ 6100 for (i = 0; i < k - 1; ++i) { 6101 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6102 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6103 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6104 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6105 } 6106 /* top */ 6107 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6108 for (o = oel - 1; o >= oet; --o) 6109 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6110 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6111 foffset = offset; 6112 } else { 6113 PetscInt dof; 6114 6115 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6116 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6117 foffset = offset; 6118 } 6119 break; 6120 case 3: 6121 /* The original hex closure is 6122 6123 {c, 6124 f_b, f_t, f_f, f_b, f_r, f_l, 6125 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6126 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6127 */ 6128 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6129 if (!continuous && d < dim) continue; 6130 /* The SEM order is 6131 Bottom Slice 6132 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6133 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6134 v_blb, {e_bb}, v_brb, 6135 6136 Middle Slice (j) 6137 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6138 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6139 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6140 6141 Top Slice 6142 v_tlf, {e_tf}, v_trf, 6143 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6144 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6145 */ 6146 if (continuous) { 6147 const PetscInt oc = 0; 6148 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6149 const PetscInt oft = ofb + PetscSqr(k - 1); 6150 const PetscInt off = oft + PetscSqr(k - 1); 6151 const PetscInt ofk = off + PetscSqr(k - 1); 6152 const PetscInt ofr = ofk + PetscSqr(k - 1); 6153 const PetscInt ofl = ofr + PetscSqr(k - 1); 6154 const PetscInt oebl = ofl + PetscSqr(k - 1); 6155 const PetscInt oebb = oebl + (k - 1); 6156 const PetscInt oebr = oebb + (k - 1); 6157 const PetscInt oebf = oebr + (k - 1); 6158 const PetscInt oetf = oebf + (k - 1); 6159 const PetscInt oetr = oetf + (k - 1); 6160 const PetscInt oetb = oetr + (k - 1); 6161 const PetscInt oetl = oetb + (k - 1); 6162 const PetscInt oerf = oetl + (k - 1); 6163 const PetscInt oelf = oerf + (k - 1); 6164 const PetscInt oelb = oelf + (k - 1); 6165 const PetscInt oerb = oelb + (k - 1); 6166 const PetscInt ovblf = oerb + (k - 1); 6167 const PetscInt ovblb = ovblf + 1; 6168 const PetscInt ovbrb = ovblb + 1; 6169 const PetscInt ovbrf = ovbrb + 1; 6170 const PetscInt ovtlf = ovbrf + 1; 6171 const PetscInt ovtrf = ovtlf + 1; 6172 const PetscInt ovtrb = ovtrf + 1; 6173 const PetscInt ovtlb = ovtrb + 1; 6174 PetscInt o, n; 6175 6176 /* Bottom Slice */ 6177 /* bottom */ 6178 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6179 for (o = oetf - 1; o >= oebf; --o) 6180 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6181 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6182 /* middle */ 6183 for (i = 0; i < k - 1; ++i) { 6184 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6185 for (n = 0; n < k - 1; ++n) { 6186 o = ofb + n * (k - 1) + i; 6187 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6188 } 6189 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6190 } 6191 /* top */ 6192 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6193 for (o = oebb; o < oebr; ++o) 6194 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6195 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6196 6197 /* Middle Slice */ 6198 for (j = 0; j < k - 1; ++j) { 6199 /* bottom */ 6200 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6201 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6202 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6203 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6204 /* middle */ 6205 for (i = 0; i < k - 1; ++i) { 6206 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6207 for (n = 0; n < k - 1; ++n) 6208 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6209 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6210 } 6211 /* top */ 6212 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6213 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6214 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6215 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6216 } 6217 6218 /* Top Slice */ 6219 /* bottom */ 6220 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6221 for (o = oetf; o < oetr; ++o) 6222 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6223 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6224 /* middle */ 6225 for (i = 0; i < k - 1; ++i) { 6226 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6227 for (n = 0; n < k - 1; ++n) 6228 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6229 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6230 } 6231 /* top */ 6232 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6233 for (o = oetl - 1; o >= oetb; --o) 6234 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6235 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6236 6237 foffset = offset; 6238 } else { 6239 PetscInt dof; 6240 6241 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6242 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6243 foffset = offset; 6244 } 6245 break; 6246 default: 6247 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6248 } 6249 } 6250 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6251 /* Check permutation */ 6252 { 6253 PetscInt *check; 6254 6255 PetscCall(PetscMalloc1(size, &check)); 6256 for (i = 0; i < size; ++i) { 6257 check[i] = -1; 6258 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6259 } 6260 for (i = 0; i < size; ++i) check[perm[i]] = i; 6261 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6262 PetscCall(PetscFree(check)); 6263 } 6264 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6265 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6266 PetscInt *loc_perm; 6267 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6268 for (PetscInt i = 0; i < size; i++) { 6269 loc_perm[i] = perm[i]; 6270 loc_perm[size + i] = size + perm[i]; 6271 } 6272 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6273 } 6274 } 6275 PetscFunctionReturn(PETSC_SUCCESS); 6276 } 6277 6278 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6279 { 6280 PetscDS prob; 6281 PetscInt depth, Nf, h; 6282 DMLabel label; 6283 6284 PetscFunctionBeginHot; 6285 PetscCall(DMGetDS(dm, &prob)); 6286 Nf = prob->Nf; 6287 label = dm->depthLabel; 6288 *dspace = NULL; 6289 if (field < Nf) { 6290 PetscObject disc = prob->disc[field]; 6291 6292 if (disc->classid == PETSCFE_CLASSID) { 6293 PetscDualSpace dsp; 6294 6295 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6296 PetscCall(DMLabelGetNumValues(label, &depth)); 6297 PetscCall(DMLabelGetValue(label, point, &h)); 6298 h = depth - 1 - h; 6299 if (h) { 6300 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6301 } else { 6302 *dspace = dsp; 6303 } 6304 } 6305 } 6306 PetscFunctionReturn(PETSC_SUCCESS); 6307 } 6308 6309 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6310 { 6311 PetscScalar *array; 6312 const PetscScalar *vArray; 6313 const PetscInt *cone, *coneO; 6314 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6315 6316 PetscFunctionBeginHot; 6317 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6318 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6319 PetscCall(DMPlexGetCone(dm, point, &cone)); 6320 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6321 if (!values || !*values) { 6322 if ((point >= pStart) && (point < pEnd)) { 6323 PetscInt dof; 6324 6325 PetscCall(PetscSectionGetDof(section, point, &dof)); 6326 size += dof; 6327 } 6328 for (p = 0; p < numPoints; ++p) { 6329 const PetscInt cp = cone[p]; 6330 PetscInt dof; 6331 6332 if ((cp < pStart) || (cp >= pEnd)) continue; 6333 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6334 size += dof; 6335 } 6336 if (!values) { 6337 if (csize) *csize = size; 6338 PetscFunctionReturn(PETSC_SUCCESS); 6339 } 6340 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6341 } else { 6342 array = *values; 6343 } 6344 size = 0; 6345 PetscCall(VecGetArrayRead(v, &vArray)); 6346 if ((point >= pStart) && (point < pEnd)) { 6347 PetscInt dof, off, d; 6348 const PetscScalar *varr; 6349 6350 PetscCall(PetscSectionGetDof(section, point, &dof)); 6351 PetscCall(PetscSectionGetOffset(section, point, &off)); 6352 varr = PetscSafePointerPlusOffset(vArray, off); 6353 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6354 size += dof; 6355 } 6356 for (p = 0; p < numPoints; ++p) { 6357 const PetscInt cp = cone[p]; 6358 PetscInt o = coneO[p]; 6359 PetscInt dof, off, d; 6360 const PetscScalar *varr; 6361 6362 if ((cp < pStart) || (cp >= pEnd)) continue; 6363 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6364 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6365 varr = PetscSafePointerPlusOffset(vArray, off); 6366 if (o >= 0) { 6367 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6368 } else { 6369 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6370 } 6371 size += dof; 6372 } 6373 PetscCall(VecRestoreArrayRead(v, &vArray)); 6374 if (!*values) { 6375 if (csize) *csize = size; 6376 *values = array; 6377 } else { 6378 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6379 *csize = size; 6380 } 6381 PetscFunctionReturn(PETSC_SUCCESS); 6382 } 6383 6384 /* Compress out points not in the section */ 6385 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6386 { 6387 const PetscInt np = *numPoints; 6388 PetscInt pStart, pEnd, p, q; 6389 6390 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6391 for (p = 0, q = 0; p < np; ++p) { 6392 const PetscInt r = points[p * 2]; 6393 if ((r >= pStart) && (r < pEnd)) { 6394 points[q * 2] = r; 6395 points[q * 2 + 1] = points[p * 2 + 1]; 6396 ++q; 6397 } 6398 } 6399 *numPoints = q; 6400 return PETSC_SUCCESS; 6401 } 6402 6403 /* Compressed closure does not apply closure permutation */ 6404 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6405 { 6406 const PetscInt *cla = NULL; 6407 PetscInt np, *pts = NULL; 6408 6409 PetscFunctionBeginHot; 6410 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6411 if (!ornt && *clPoints) { 6412 PetscInt dof, off; 6413 6414 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6415 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6416 PetscCall(ISGetIndices(*clPoints, &cla)); 6417 np = dof / 2; 6418 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6419 } else { 6420 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6421 PetscCall(CompressPoints_Private(section, &np, pts)); 6422 } 6423 *numPoints = np; 6424 *points = pts; 6425 *clp = cla; 6426 PetscFunctionReturn(PETSC_SUCCESS); 6427 } 6428 6429 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6430 { 6431 PetscFunctionBeginHot; 6432 if (!*clPoints) { 6433 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6434 } else { 6435 PetscCall(ISRestoreIndices(*clPoints, clp)); 6436 } 6437 *numPoints = 0; 6438 *points = NULL; 6439 *clSec = NULL; 6440 *clPoints = NULL; 6441 *clp = NULL; 6442 PetscFunctionReturn(PETSC_SUCCESS); 6443 } 6444 6445 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6446 { 6447 PetscInt offset = 0, p; 6448 const PetscInt **perms = NULL; 6449 const PetscScalar **flips = NULL; 6450 6451 PetscFunctionBeginHot; 6452 *size = 0; 6453 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6454 for (p = 0; p < numPoints; p++) { 6455 const PetscInt point = points[2 * p]; 6456 const PetscInt *perm = perms ? perms[p] : NULL; 6457 const PetscScalar *flip = flips ? flips[p] : NULL; 6458 PetscInt dof, off, d; 6459 const PetscScalar *varr; 6460 6461 PetscCall(PetscSectionGetDof(section, point, &dof)); 6462 PetscCall(PetscSectionGetOffset(section, point, &off)); 6463 varr = PetscSafePointerPlusOffset(vArray, off); 6464 if (clperm) { 6465 if (perm) { 6466 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6467 } else { 6468 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6469 } 6470 if (flip) { 6471 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6472 } 6473 } else { 6474 if (perm) { 6475 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6476 } else { 6477 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6478 } 6479 if (flip) { 6480 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6481 } 6482 } 6483 offset += dof; 6484 } 6485 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6486 *size = offset; 6487 PetscFunctionReturn(PETSC_SUCCESS); 6488 } 6489 6490 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[]) 6491 { 6492 PetscInt offset = 0, f; 6493 6494 PetscFunctionBeginHot; 6495 *size = 0; 6496 for (f = 0; f < numFields; ++f) { 6497 PetscInt p; 6498 const PetscInt **perms = NULL; 6499 const PetscScalar **flips = NULL; 6500 6501 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6502 for (p = 0; p < numPoints; p++) { 6503 const PetscInt point = points[2 * p]; 6504 PetscInt fdof, foff, b; 6505 const PetscScalar *varr; 6506 const PetscInt *perm = perms ? perms[p] : NULL; 6507 const PetscScalar *flip = flips ? flips[p] : NULL; 6508 6509 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6510 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6511 varr = &vArray[foff]; 6512 if (clperm) { 6513 if (perm) { 6514 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6515 } else { 6516 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6517 } 6518 if (flip) { 6519 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6520 } 6521 } else { 6522 if (perm) { 6523 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6524 } else { 6525 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6526 } 6527 if (flip) { 6528 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6529 } 6530 } 6531 offset += fdof; 6532 } 6533 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6534 } 6535 *size = offset; 6536 PetscFunctionReturn(PETSC_SUCCESS); 6537 } 6538 6539 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6540 { 6541 PetscSection clSection; 6542 IS clPoints; 6543 PetscInt *points = NULL; 6544 const PetscInt *clp, *perm = NULL; 6545 PetscInt depth, numFields, numPoints, asize; 6546 6547 PetscFunctionBeginHot; 6548 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6549 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6550 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6551 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6552 PetscCall(DMPlexGetDepth(dm, &depth)); 6553 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6554 if (depth == 1 && numFields < 2) { 6555 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6556 PetscFunctionReturn(PETSC_SUCCESS); 6557 } 6558 /* Get points */ 6559 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6560 /* Get sizes */ 6561 asize = 0; 6562 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6563 PetscInt dof; 6564 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6565 asize += dof; 6566 } 6567 if (values) { 6568 const PetscScalar *vArray; 6569 PetscInt size; 6570 6571 if (*values) { 6572 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); 6573 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6574 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6575 PetscCall(VecGetArrayRead(v, &vArray)); 6576 /* Get values */ 6577 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6578 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6579 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6580 /* Cleanup array */ 6581 PetscCall(VecRestoreArrayRead(v, &vArray)); 6582 } 6583 if (csize) *csize = asize; 6584 /* Cleanup points */ 6585 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6586 PetscFunctionReturn(PETSC_SUCCESS); 6587 } 6588 6589 /*@C 6590 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6591 6592 Not collective 6593 6594 Input Parameters: 6595 + dm - The `DM` 6596 . section - The section describing the layout in `v`, or `NULL` to use the default section 6597 . v - The local vector 6598 - point - The point in the `DM` 6599 6600 Input/Output Parameters: 6601 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6602 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6603 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6604 6605 Level: intermediate 6606 6607 Notes: 6608 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6609 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6610 assembly function, and a user may already have allocated storage for this operation. 6611 6612 A typical use could be 6613 .vb 6614 values = NULL; 6615 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6616 for (cl = 0; cl < clSize; ++cl) { 6617 <Compute on closure> 6618 } 6619 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6620 .ve 6621 or 6622 .vb 6623 PetscMalloc1(clMaxSize, &values); 6624 for (p = pStart; p < pEnd; ++p) { 6625 clSize = clMaxSize; 6626 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6627 for (cl = 0; cl < clSize; ++cl) { 6628 <Compute on closure> 6629 } 6630 } 6631 PetscFree(values); 6632 .ve 6633 6634 Fortran Notes: 6635 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6636 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6637 6638 `values` must be declared with 6639 .vb 6640 PetscScalar,dimension(:),pointer :: values 6641 .ve 6642 and it will be allocated internally by PETSc to hold the values returned 6643 6644 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6645 @*/ 6646 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6647 { 6648 PetscFunctionBeginHot; 6649 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6650 PetscFunctionReturn(PETSC_SUCCESS); 6651 } 6652 6653 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6654 { 6655 DMLabel depthLabel; 6656 PetscSection clSection; 6657 IS clPoints; 6658 PetscScalar *array; 6659 const PetscScalar *vArray; 6660 PetscInt *points = NULL; 6661 const PetscInt *clp, *perm = NULL; 6662 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6663 6664 PetscFunctionBeginHot; 6665 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6666 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6667 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6668 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6669 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6670 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6671 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6672 if (mdepth == 1 && numFields < 2) { 6673 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6674 PetscFunctionReturn(PETSC_SUCCESS); 6675 } 6676 /* Get points */ 6677 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6678 for (clsize = 0, p = 0; p < Np; p++) { 6679 PetscInt dof; 6680 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6681 clsize += dof; 6682 } 6683 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6684 /* Filter points */ 6685 for (p = 0; p < numPoints * 2; p += 2) { 6686 PetscInt dep; 6687 6688 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6689 if (dep != depth) continue; 6690 points[Np * 2 + 0] = points[p]; 6691 points[Np * 2 + 1] = points[p + 1]; 6692 ++Np; 6693 } 6694 /* Get array */ 6695 if (!values || !*values) { 6696 PetscInt asize = 0, dof; 6697 6698 for (p = 0; p < Np * 2; p += 2) { 6699 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6700 asize += dof; 6701 } 6702 if (!values) { 6703 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6704 if (csize) *csize = asize; 6705 PetscFunctionReturn(PETSC_SUCCESS); 6706 } 6707 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6708 } else { 6709 array = *values; 6710 } 6711 PetscCall(VecGetArrayRead(v, &vArray)); 6712 /* Get values */ 6713 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6714 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6715 /* Cleanup points */ 6716 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6717 /* Cleanup array */ 6718 PetscCall(VecRestoreArrayRead(v, &vArray)); 6719 if (!*values) { 6720 if (csize) *csize = size; 6721 *values = array; 6722 } else { 6723 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6724 *csize = size; 6725 } 6726 PetscFunctionReturn(PETSC_SUCCESS); 6727 } 6728 6729 /*@C 6730 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6731 6732 Not collective 6733 6734 Input Parameters: 6735 + dm - The `DM` 6736 . section - The section describing the layout in `v`, or `NULL` to use the default section 6737 . v - The local vector 6738 . point - The point in the `DM` 6739 . csize - The number of values in the closure, or `NULL` 6740 - values - The array of values 6741 6742 Level: intermediate 6743 6744 Note: 6745 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6746 6747 Fortran Note: 6748 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6749 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6750 6751 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6752 @*/ 6753 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6754 { 6755 PetscInt size = 0; 6756 6757 PetscFunctionBegin; 6758 /* Should work without recalculating size */ 6759 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6760 *values = NULL; 6761 PetscFunctionReturn(PETSC_SUCCESS); 6762 } 6763 6764 static inline void add(PetscScalar *x, PetscScalar y) 6765 { 6766 *x += y; 6767 } 6768 static inline void insert(PetscScalar *x, PetscScalar y) 6769 { 6770 *x = y; 6771 } 6772 6773 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[]) 6774 { 6775 PetscInt cdof; /* The number of constraints on this point */ 6776 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6777 PetscScalar *a; 6778 PetscInt off, cind = 0, k; 6779 6780 PetscFunctionBegin; 6781 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6782 PetscCall(PetscSectionGetOffset(section, point, &off)); 6783 a = &array[off]; 6784 if (!cdof || setBC) { 6785 if (clperm) { 6786 if (perm) { 6787 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6788 } else { 6789 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6790 } 6791 } else { 6792 if (perm) { 6793 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6794 } else { 6795 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6796 } 6797 } 6798 } else { 6799 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6800 if (clperm) { 6801 if (perm) { 6802 for (k = 0; k < dof; ++k) { 6803 if ((cind < cdof) && (k == cdofs[cind])) { 6804 ++cind; 6805 continue; 6806 } 6807 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6808 } 6809 } else { 6810 for (k = 0; k < dof; ++k) { 6811 if ((cind < cdof) && (k == cdofs[cind])) { 6812 ++cind; 6813 continue; 6814 } 6815 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6816 } 6817 } 6818 } else { 6819 if (perm) { 6820 for (k = 0; k < dof; ++k) { 6821 if ((cind < cdof) && (k == cdofs[cind])) { 6822 ++cind; 6823 continue; 6824 } 6825 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6826 } 6827 } else { 6828 for (k = 0; k < dof; ++k) { 6829 if ((cind < cdof) && (k == cdofs[cind])) { 6830 ++cind; 6831 continue; 6832 } 6833 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6834 } 6835 } 6836 } 6837 } 6838 PetscFunctionReturn(PETSC_SUCCESS); 6839 } 6840 6841 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[]) 6842 { 6843 PetscInt cdof; /* The number of constraints on this point */ 6844 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6845 PetscScalar *a; 6846 PetscInt off, cind = 0, k; 6847 6848 PetscFunctionBegin; 6849 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6850 PetscCall(PetscSectionGetOffset(section, point, &off)); 6851 a = &array[off]; 6852 if (cdof) { 6853 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6854 if (clperm) { 6855 if (perm) { 6856 for (k = 0; k < dof; ++k) { 6857 if ((cind < cdof) && (k == cdofs[cind])) { 6858 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6859 cind++; 6860 } 6861 } 6862 } else { 6863 for (k = 0; k < dof; ++k) { 6864 if ((cind < cdof) && (k == cdofs[cind])) { 6865 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6866 cind++; 6867 } 6868 } 6869 } 6870 } else { 6871 if (perm) { 6872 for (k = 0; k < dof; ++k) { 6873 if ((cind < cdof) && (k == cdofs[cind])) { 6874 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6875 cind++; 6876 } 6877 } 6878 } else { 6879 for (k = 0; k < dof; ++k) { 6880 if ((cind < cdof) && (k == cdofs[cind])) { 6881 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6882 cind++; 6883 } 6884 } 6885 } 6886 } 6887 } 6888 PetscFunctionReturn(PETSC_SUCCESS); 6889 } 6890 6891 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[]) 6892 { 6893 PetscScalar *a; 6894 PetscInt fdof, foff, fcdof, foffset = *offset; 6895 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6896 PetscInt cind = 0, b; 6897 6898 PetscFunctionBegin; 6899 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6900 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6901 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6902 a = &array[foff]; 6903 if (!fcdof || setBC) { 6904 if (clperm) { 6905 if (perm) { 6906 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6907 } else { 6908 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6909 } 6910 } else { 6911 if (perm) { 6912 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6913 } else { 6914 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6915 } 6916 } 6917 } else { 6918 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6919 if (clperm) { 6920 if (perm) { 6921 for (b = 0; b < fdof; b++) { 6922 if ((cind < fcdof) && (b == fcdofs[cind])) { 6923 ++cind; 6924 continue; 6925 } 6926 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6927 } 6928 } else { 6929 for (b = 0; b < fdof; b++) { 6930 if ((cind < fcdof) && (b == fcdofs[cind])) { 6931 ++cind; 6932 continue; 6933 } 6934 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6935 } 6936 } 6937 } else { 6938 if (perm) { 6939 for (b = 0; b < fdof; b++) { 6940 if ((cind < fcdof) && (b == fcdofs[cind])) { 6941 ++cind; 6942 continue; 6943 } 6944 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6945 } 6946 } else { 6947 for (b = 0; b < fdof; b++) { 6948 if ((cind < fcdof) && (b == fcdofs[cind])) { 6949 ++cind; 6950 continue; 6951 } 6952 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6953 } 6954 } 6955 } 6956 } 6957 *offset += fdof; 6958 PetscFunctionReturn(PETSC_SUCCESS); 6959 } 6960 6961 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[]) 6962 { 6963 PetscScalar *a; 6964 PetscInt fdof, foff, fcdof, foffset = *offset; 6965 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6966 PetscInt Nc, cind = 0, ncind = 0, b; 6967 PetscBool ncSet, fcSet; 6968 6969 PetscFunctionBegin; 6970 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6971 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6972 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6973 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6974 a = &array[foff]; 6975 if (fcdof) { 6976 /* We just override fcdof and fcdofs with Ncc and comps */ 6977 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6978 if (clperm) { 6979 if (perm) { 6980 if (comps) { 6981 for (b = 0; b < fdof; b++) { 6982 ncSet = fcSet = PETSC_FALSE; 6983 if (b % Nc == comps[ncind]) { 6984 ncind = (ncind + 1) % Ncc; 6985 ncSet = PETSC_TRUE; 6986 } 6987 if ((cind < fcdof) && (b == fcdofs[cind])) { 6988 ++cind; 6989 fcSet = PETSC_TRUE; 6990 } 6991 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6992 } 6993 } else { 6994 for (b = 0; b < fdof; b++) { 6995 if ((cind < fcdof) && (b == fcdofs[cind])) { 6996 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6997 ++cind; 6998 } 6999 } 7000 } 7001 } else { 7002 if (comps) { 7003 for (b = 0; b < fdof; b++) { 7004 ncSet = fcSet = PETSC_FALSE; 7005 if (b % Nc == comps[ncind]) { 7006 ncind = (ncind + 1) % Ncc; 7007 ncSet = PETSC_TRUE; 7008 } 7009 if ((cind < fcdof) && (b == fcdofs[cind])) { 7010 ++cind; 7011 fcSet = PETSC_TRUE; 7012 } 7013 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7014 } 7015 } else { 7016 for (b = 0; b < fdof; b++) { 7017 if ((cind < fcdof) && (b == fcdofs[cind])) { 7018 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7019 ++cind; 7020 } 7021 } 7022 } 7023 } 7024 } else { 7025 if (perm) { 7026 if (comps) { 7027 for (b = 0; b < fdof; b++) { 7028 ncSet = fcSet = PETSC_FALSE; 7029 if (b % Nc == comps[ncind]) { 7030 ncind = (ncind + 1) % Ncc; 7031 ncSet = PETSC_TRUE; 7032 } 7033 if ((cind < fcdof) && (b == fcdofs[cind])) { 7034 ++cind; 7035 fcSet = PETSC_TRUE; 7036 } 7037 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7038 } 7039 } else { 7040 for (b = 0; b < fdof; b++) { 7041 if ((cind < fcdof) && (b == fcdofs[cind])) { 7042 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7043 ++cind; 7044 } 7045 } 7046 } 7047 } else { 7048 if (comps) { 7049 for (b = 0; b < fdof; b++) { 7050 ncSet = fcSet = PETSC_FALSE; 7051 if (b % Nc == comps[ncind]) { 7052 ncind = (ncind + 1) % Ncc; 7053 ncSet = PETSC_TRUE; 7054 } 7055 if ((cind < fcdof) && (b == fcdofs[cind])) { 7056 ++cind; 7057 fcSet = PETSC_TRUE; 7058 } 7059 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7060 } 7061 } else { 7062 for (b = 0; b < fdof; b++) { 7063 if ((cind < fcdof) && (b == fcdofs[cind])) { 7064 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7065 ++cind; 7066 } 7067 } 7068 } 7069 } 7070 } 7071 } 7072 *offset += fdof; 7073 PetscFunctionReturn(PETSC_SUCCESS); 7074 } 7075 7076 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7077 { 7078 PetscScalar *array; 7079 const PetscInt *cone, *coneO; 7080 PetscInt pStart, pEnd, p, numPoints, off, dof; 7081 7082 PetscFunctionBeginHot; 7083 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7084 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7085 PetscCall(DMPlexGetCone(dm, point, &cone)); 7086 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7087 PetscCall(VecGetArray(v, &array)); 7088 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7089 const PetscInt cp = !p ? point : cone[p - 1]; 7090 const PetscInt o = !p ? 0 : coneO[p - 1]; 7091 7092 if ((cp < pStart) || (cp >= pEnd)) { 7093 dof = 0; 7094 continue; 7095 } 7096 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7097 /* ADD_VALUES */ 7098 { 7099 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7100 PetscScalar *a; 7101 PetscInt cdof, coff, cind = 0, k; 7102 7103 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7104 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7105 a = &array[coff]; 7106 if (!cdof) { 7107 if (o >= 0) { 7108 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7109 } else { 7110 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7111 } 7112 } else { 7113 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7114 if (o >= 0) { 7115 for (k = 0; k < dof; ++k) { 7116 if ((cind < cdof) && (k == cdofs[cind])) { 7117 ++cind; 7118 continue; 7119 } 7120 a[k] += values[off + k]; 7121 } 7122 } else { 7123 for (k = 0; k < dof; ++k) { 7124 if ((cind < cdof) && (k == cdofs[cind])) { 7125 ++cind; 7126 continue; 7127 } 7128 a[k] += values[off + dof - k - 1]; 7129 } 7130 } 7131 } 7132 } 7133 } 7134 PetscCall(VecRestoreArray(v, &array)); 7135 PetscFunctionReturn(PETSC_SUCCESS); 7136 } 7137 7138 /*@C 7139 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7140 7141 Not collective 7142 7143 Input Parameters: 7144 + dm - The `DM` 7145 . section - The section describing the layout in `v`, or `NULL` to use the default section 7146 . v - The local vector 7147 . point - The point in the `DM` 7148 . values - The array of values 7149 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7150 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7151 7152 Level: intermediate 7153 7154 Note: 7155 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7156 7157 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7158 @*/ 7159 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7160 { 7161 PetscSection clSection; 7162 IS clPoints; 7163 PetscScalar *array; 7164 PetscInt *points = NULL; 7165 const PetscInt *clp, *clperm = NULL; 7166 PetscInt depth, numFields, numPoints, p, clsize; 7167 7168 PetscFunctionBeginHot; 7169 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7170 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7171 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7172 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7173 PetscCall(DMPlexGetDepth(dm, &depth)); 7174 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7175 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7176 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7177 PetscFunctionReturn(PETSC_SUCCESS); 7178 } 7179 /* Get points */ 7180 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7181 for (clsize = 0, p = 0; p < numPoints; p++) { 7182 PetscInt dof; 7183 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7184 clsize += dof; 7185 } 7186 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7187 /* Get array */ 7188 PetscCall(VecGetArray(v, &array)); 7189 /* Get values */ 7190 if (numFields > 0) { 7191 PetscInt offset = 0, f; 7192 for (f = 0; f < numFields; ++f) { 7193 const PetscInt **perms = NULL; 7194 const PetscScalar **flips = NULL; 7195 7196 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7197 switch (mode) { 7198 case INSERT_VALUES: 7199 for (p = 0; p < numPoints; p++) { 7200 const PetscInt point = points[2 * p]; 7201 const PetscInt *perm = perms ? perms[p] : NULL; 7202 const PetscScalar *flip = flips ? flips[p] : NULL; 7203 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7204 } 7205 break; 7206 case INSERT_ALL_VALUES: 7207 for (p = 0; p < numPoints; p++) { 7208 const PetscInt point = points[2 * p]; 7209 const PetscInt *perm = perms ? perms[p] : NULL; 7210 const PetscScalar *flip = flips ? flips[p] : NULL; 7211 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7212 } 7213 break; 7214 case INSERT_BC_VALUES: 7215 for (p = 0; p < numPoints; p++) { 7216 const PetscInt point = points[2 * p]; 7217 const PetscInt *perm = perms ? perms[p] : NULL; 7218 const PetscScalar *flip = flips ? flips[p] : NULL; 7219 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7220 } 7221 break; 7222 case ADD_VALUES: 7223 for (p = 0; p < numPoints; p++) { 7224 const PetscInt point = points[2 * p]; 7225 const PetscInt *perm = perms ? perms[p] : NULL; 7226 const PetscScalar *flip = flips ? flips[p] : NULL; 7227 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7228 } 7229 break; 7230 case ADD_ALL_VALUES: 7231 for (p = 0; p < numPoints; p++) { 7232 const PetscInt point = points[2 * p]; 7233 const PetscInt *perm = perms ? perms[p] : NULL; 7234 const PetscScalar *flip = flips ? flips[p] : NULL; 7235 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7236 } 7237 break; 7238 case ADD_BC_VALUES: 7239 for (p = 0; p < numPoints; p++) { 7240 const PetscInt point = points[2 * p]; 7241 const PetscInt *perm = perms ? perms[p] : NULL; 7242 const PetscScalar *flip = flips ? flips[p] : NULL; 7243 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7244 } 7245 break; 7246 default: 7247 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7248 } 7249 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7250 } 7251 } else { 7252 PetscInt dof, off; 7253 const PetscInt **perms = NULL; 7254 const PetscScalar **flips = NULL; 7255 7256 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7257 switch (mode) { 7258 case INSERT_VALUES: 7259 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7260 const PetscInt point = points[2 * p]; 7261 const PetscInt *perm = perms ? perms[p] : NULL; 7262 const PetscScalar *flip = flips ? flips[p] : NULL; 7263 PetscCall(PetscSectionGetDof(section, point, &dof)); 7264 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7265 } 7266 break; 7267 case INSERT_ALL_VALUES: 7268 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7269 const PetscInt point = points[2 * p]; 7270 const PetscInt *perm = perms ? perms[p] : NULL; 7271 const PetscScalar *flip = flips ? flips[p] : NULL; 7272 PetscCall(PetscSectionGetDof(section, point, &dof)); 7273 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7274 } 7275 break; 7276 case INSERT_BC_VALUES: 7277 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7278 const PetscInt point = points[2 * p]; 7279 const PetscInt *perm = perms ? perms[p] : NULL; 7280 const PetscScalar *flip = flips ? flips[p] : NULL; 7281 PetscCall(PetscSectionGetDof(section, point, &dof)); 7282 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7283 } 7284 break; 7285 case ADD_VALUES: 7286 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7287 const PetscInt point = points[2 * p]; 7288 const PetscInt *perm = perms ? perms[p] : NULL; 7289 const PetscScalar *flip = flips ? flips[p] : NULL; 7290 PetscCall(PetscSectionGetDof(section, point, &dof)); 7291 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7292 } 7293 break; 7294 case ADD_ALL_VALUES: 7295 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7296 const PetscInt point = points[2 * p]; 7297 const PetscInt *perm = perms ? perms[p] : NULL; 7298 const PetscScalar *flip = flips ? flips[p] : NULL; 7299 PetscCall(PetscSectionGetDof(section, point, &dof)); 7300 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7301 } 7302 break; 7303 case ADD_BC_VALUES: 7304 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7305 const PetscInt point = points[2 * p]; 7306 const PetscInt *perm = perms ? perms[p] : NULL; 7307 const PetscScalar *flip = flips ? flips[p] : NULL; 7308 PetscCall(PetscSectionGetDof(section, point, &dof)); 7309 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7310 } 7311 break; 7312 default: 7313 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7314 } 7315 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7316 } 7317 /* Cleanup points */ 7318 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7319 /* Cleanup array */ 7320 PetscCall(VecRestoreArray(v, &array)); 7321 PetscFunctionReturn(PETSC_SUCCESS); 7322 } 7323 7324 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7325 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7326 { 7327 PetscFunctionBegin; 7328 *contains = PETSC_TRUE; 7329 if (label) { 7330 PetscInt fdof; 7331 7332 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7333 if (!*contains) { 7334 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7335 *offset += fdof; 7336 PetscFunctionReturn(PETSC_SUCCESS); 7337 } 7338 } 7339 PetscFunctionReturn(PETSC_SUCCESS); 7340 } 7341 7342 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7343 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) 7344 { 7345 PetscSection clSection; 7346 IS clPoints; 7347 PetscScalar *array; 7348 PetscInt *points = NULL; 7349 const PetscInt *clp; 7350 PetscInt numFields, numPoints, p; 7351 PetscInt offset = 0, f; 7352 7353 PetscFunctionBeginHot; 7354 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7355 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7356 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7357 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7358 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7359 /* Get points */ 7360 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7361 /* Get array */ 7362 PetscCall(VecGetArray(v, &array)); 7363 /* Get values */ 7364 for (f = 0; f < numFields; ++f) { 7365 const PetscInt **perms = NULL; 7366 const PetscScalar **flips = NULL; 7367 PetscBool contains; 7368 7369 if (!fieldActive[f]) { 7370 for (p = 0; p < numPoints * 2; p += 2) { 7371 PetscInt fdof; 7372 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7373 offset += fdof; 7374 } 7375 continue; 7376 } 7377 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7378 switch (mode) { 7379 case INSERT_VALUES: 7380 for (p = 0; p < numPoints; p++) { 7381 const PetscInt point = points[2 * p]; 7382 const PetscInt *perm = perms ? perms[p] : NULL; 7383 const PetscScalar *flip = flips ? flips[p] : NULL; 7384 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7385 if (!contains) continue; 7386 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7387 } 7388 break; 7389 case INSERT_ALL_VALUES: 7390 for (p = 0; p < numPoints; p++) { 7391 const PetscInt point = points[2 * p]; 7392 const PetscInt *perm = perms ? perms[p] : NULL; 7393 const PetscScalar *flip = flips ? flips[p] : NULL; 7394 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7395 if (!contains) continue; 7396 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7397 } 7398 break; 7399 case INSERT_BC_VALUES: 7400 for (p = 0; p < numPoints; p++) { 7401 const PetscInt point = points[2 * p]; 7402 const PetscInt *perm = perms ? perms[p] : NULL; 7403 const PetscScalar *flip = flips ? flips[p] : NULL; 7404 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7405 if (!contains) continue; 7406 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7407 } 7408 break; 7409 case ADD_VALUES: 7410 for (p = 0; p < numPoints; p++) { 7411 const PetscInt point = points[2 * p]; 7412 const PetscInt *perm = perms ? perms[p] : NULL; 7413 const PetscScalar *flip = flips ? flips[p] : NULL; 7414 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7415 if (!contains) continue; 7416 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7417 } 7418 break; 7419 case ADD_ALL_VALUES: 7420 for (p = 0; p < numPoints; p++) { 7421 const PetscInt point = points[2 * p]; 7422 const PetscInt *perm = perms ? perms[p] : NULL; 7423 const PetscScalar *flip = flips ? flips[p] : NULL; 7424 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7425 if (!contains) continue; 7426 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7427 } 7428 break; 7429 default: 7430 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7431 } 7432 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7433 } 7434 /* Cleanup points */ 7435 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7436 /* Cleanup array */ 7437 PetscCall(VecRestoreArray(v, &array)); 7438 PetscFunctionReturn(PETSC_SUCCESS); 7439 } 7440 7441 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7442 { 7443 PetscMPIInt rank; 7444 PetscInt i, j; 7445 7446 PetscFunctionBegin; 7447 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7448 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7449 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7450 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7451 numCIndices = numCIndices ? numCIndices : numRIndices; 7452 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7453 for (i = 0; i < numRIndices; i++) { 7454 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7455 for (j = 0; j < numCIndices; j++) { 7456 #if defined(PETSC_USE_COMPLEX) 7457 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7458 #else 7459 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7460 #endif 7461 } 7462 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7463 } 7464 PetscFunctionReturn(PETSC_SUCCESS); 7465 } 7466 7467 /* 7468 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7469 7470 Input Parameters: 7471 + section - The section for this data layout 7472 . islocal - Is the section (and thus indices being requested) local or global? 7473 . point - The point contributing dofs with these indices 7474 . off - The global offset of this point 7475 . loff - The local offset of each field 7476 . setBC - The flag determining whether to include indices of boundary values 7477 . perm - A permutation of the dofs on this point, or NULL 7478 - indperm - A permutation of the entire indices array, or NULL 7479 7480 Output Parameter: 7481 . indices - Indices for dofs on this point 7482 7483 Level: developer 7484 7485 Note: The indices could be local or global, depending on the value of 'off'. 7486 */ 7487 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7488 { 7489 PetscInt dof; /* The number of unknowns on this point */ 7490 PetscInt cdof; /* The number of constraints on this point */ 7491 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7492 PetscInt cind = 0, k; 7493 7494 PetscFunctionBegin; 7495 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7496 PetscCall(PetscSectionGetDof(section, point, &dof)); 7497 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7498 if (!cdof || setBC) { 7499 for (k = 0; k < dof; ++k) { 7500 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7501 const PetscInt ind = indperm ? indperm[preind] : preind; 7502 7503 indices[ind] = off + k; 7504 } 7505 } else { 7506 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7507 for (k = 0; k < dof; ++k) { 7508 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7509 const PetscInt ind = indperm ? indperm[preind] : preind; 7510 7511 if ((cind < cdof) && (k == cdofs[cind])) { 7512 /* Insert check for returning constrained indices */ 7513 indices[ind] = -(off + k + 1); 7514 ++cind; 7515 } else { 7516 indices[ind] = off + k - (islocal ? 0 : cind); 7517 } 7518 } 7519 } 7520 *loff += dof; 7521 PetscFunctionReturn(PETSC_SUCCESS); 7522 } 7523 7524 /* 7525 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7526 7527 Input Parameters: 7528 + section - a section (global or local) 7529 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7530 . point - point within section 7531 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7532 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7533 . setBC - identify constrained (boundary condition) points via involution. 7534 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7535 . permsoff - offset 7536 - indperm - index permutation 7537 7538 Output Parameter: 7539 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7540 . indices - array to hold indices (as defined by section) of each dof associated with point 7541 7542 Notes: 7543 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7544 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7545 in the local vector. 7546 7547 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7548 significant). It is invalid to call with a global section and setBC=true. 7549 7550 Developer Note: 7551 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7552 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7553 offset could be obtained from the section instead of passing it explicitly as we do now. 7554 7555 Example: 7556 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7557 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7558 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7559 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. 7560 7561 Level: developer 7562 */ 7563 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[]) 7564 { 7565 PetscInt numFields, foff, f; 7566 7567 PetscFunctionBegin; 7568 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7569 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7570 for (f = 0, foff = 0; f < numFields; ++f) { 7571 PetscInt fdof, cfdof; 7572 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7573 PetscInt cind = 0, b; 7574 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7575 7576 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7577 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7578 if (!cfdof || setBC) { 7579 for (b = 0; b < fdof; ++b) { 7580 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7581 const PetscInt ind = indperm ? indperm[preind] : preind; 7582 7583 indices[ind] = off + foff + b; 7584 } 7585 } else { 7586 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7587 for (b = 0; b < fdof; ++b) { 7588 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7589 const PetscInt ind = indperm ? indperm[preind] : preind; 7590 7591 if ((cind < cfdof) && (b == fcdofs[cind])) { 7592 indices[ind] = -(off + foff + b + 1); 7593 ++cind; 7594 } else { 7595 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7596 } 7597 } 7598 } 7599 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7600 foffs[f] += fdof; 7601 } 7602 PetscFunctionReturn(PETSC_SUCCESS); 7603 } 7604 7605 /* 7606 This version believes the globalSection offsets for each field, rather than just the point offset 7607 7608 . foffs - The offset into 'indices' for each field, since it is segregated by field 7609 7610 Notes: 7611 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7612 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7613 */ 7614 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7615 { 7616 PetscInt numFields, foff, f; 7617 7618 PetscFunctionBegin; 7619 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7620 for (f = 0; f < numFields; ++f) { 7621 PetscInt fdof, cfdof; 7622 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7623 PetscInt cind = 0, b; 7624 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7625 7626 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7627 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7628 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7629 if (!cfdof) { 7630 for (b = 0; b < fdof; ++b) { 7631 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7632 const PetscInt ind = indperm ? indperm[preind] : preind; 7633 7634 indices[ind] = foff + b; 7635 } 7636 } else { 7637 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7638 for (b = 0; b < fdof; ++b) { 7639 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7640 const PetscInt ind = indperm ? indperm[preind] : preind; 7641 7642 if ((cind < cfdof) && (b == fcdofs[cind])) { 7643 indices[ind] = -(foff + b + 1); 7644 ++cind; 7645 } else { 7646 indices[ind] = foff + b - cind; 7647 } 7648 } 7649 } 7650 foffs[f] += fdof; 7651 } 7652 PetscFunctionReturn(PETSC_SUCCESS); 7653 } 7654 7655 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7656 { 7657 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7658 7659 PetscFunctionBegin; 7660 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7661 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7662 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7663 for (PetscInt p = 0; p < nPoints; p++) { 7664 PetscInt b = pnts[2 * p]; 7665 PetscInt bSecDof = 0, bOff; 7666 PetscInt cSecDof = 0; 7667 PetscSection indices_section; 7668 7669 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7670 if (!bSecDof) continue; 7671 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7672 indices_section = cSecDof > 0 ? cSec : section; 7673 if (numFields) { 7674 PetscInt fStart[32], fEnd[32]; 7675 7676 fStart[0] = 0; 7677 fEnd[0] = 0; 7678 for (PetscInt f = 0; f < numFields; f++) { 7679 PetscInt fDof = 0; 7680 7681 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7682 fStart[f + 1] = fStart[f] + fDof; 7683 fEnd[f + 1] = fStart[f + 1]; 7684 } 7685 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7686 // only apply permutations on one side 7687 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7688 for (PetscInt f = 0; f < numFields; f++) { 7689 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7690 } 7691 } else { 7692 PetscInt bEnd = 0; 7693 7694 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7695 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7696 7697 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7698 } 7699 } 7700 PetscFunctionReturn(PETSC_SUCCESS); 7701 } 7702 7703 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[]) 7704 { 7705 Mat cMat; 7706 PetscSection aSec, cSec; 7707 IS aIS; 7708 PetscInt aStart = -1, aEnd = -1; 7709 PetscInt sStart = -1, sEnd = -1; 7710 PetscInt cStart = -1, cEnd = -1; 7711 const PetscInt *anchors; 7712 PetscInt numFields, p; 7713 PetscInt newNumPoints = 0, newNumIndices = 0; 7714 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7715 PetscInt oldOffsets[32]; 7716 PetscInt newOffsets[32]; 7717 PetscInt oldOffsetsCopy[32]; 7718 PetscInt newOffsetsCopy[32]; 7719 PetscScalar *modMat = NULL; 7720 PetscBool anyConstrained = PETSC_FALSE; 7721 7722 PetscFunctionBegin; 7723 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7724 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7725 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7726 7727 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7728 /* if there are point-to-point constraints */ 7729 if (aSec) { 7730 PetscCall(PetscArrayzero(newOffsets, 32)); 7731 PetscCall(PetscArrayzero(oldOffsets, 32)); 7732 PetscCall(ISGetIndices(aIS, &anchors)); 7733 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7734 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7735 /* figure out how many points are going to be in the new element matrix 7736 * (we allow double counting, because it's all just going to be summed 7737 * into the global matrix anyway) */ 7738 for (p = 0; p < 2 * numPoints; p += 2) { 7739 PetscInt b = points[p]; 7740 PetscInt bDof = 0, bSecDof = 0; 7741 7742 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7743 if (!bSecDof) continue; 7744 7745 for (PetscInt f = 0; f < numFields; f++) { 7746 PetscInt fDof = 0; 7747 7748 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7749 oldOffsets[f + 1] += fDof; 7750 } 7751 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7752 if (bDof) { 7753 /* this point is constrained */ 7754 /* it is going to be replaced by its anchors */ 7755 PetscInt bOff, q; 7756 7757 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7758 for (q = 0; q < bDof; q++) { 7759 PetscInt a = anchors[bOff + q]; 7760 PetscInt aDof = 0; 7761 7762 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7763 if (aDof) { 7764 anyConstrained = PETSC_TRUE; 7765 newNumPoints += 1; 7766 } 7767 newNumIndices += aDof; 7768 for (PetscInt f = 0; f < numFields; ++f) { 7769 PetscInt fDof = 0; 7770 7771 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7772 newOffsets[f + 1] += fDof; 7773 } 7774 } 7775 } else { 7776 /* this point is not constrained */ 7777 newNumPoints++; 7778 newNumIndices += bSecDof; 7779 for (PetscInt f = 0; f < numFields; ++f) { 7780 PetscInt fDof; 7781 7782 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7783 newOffsets[f + 1] += fDof; 7784 } 7785 } 7786 } 7787 } 7788 if (!anyConstrained) { 7789 if (outNumPoints) *outNumPoints = 0; 7790 if (outNumIndices) *outNumIndices = 0; 7791 if (outPoints) *outPoints = NULL; 7792 if (outMat) *outMat = NULL; 7793 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7794 PetscFunctionReturn(PETSC_SUCCESS); 7795 } 7796 7797 if (outNumPoints) *outNumPoints = newNumPoints; 7798 if (outNumIndices) *outNumIndices = newNumIndices; 7799 7800 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7801 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7802 7803 if (!outPoints && !outMat) { 7804 if (offsets) { 7805 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7806 } 7807 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7808 PetscFunctionReturn(PETSC_SUCCESS); 7809 } 7810 7811 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7812 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7813 7814 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7815 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7816 7817 /* output arrays */ 7818 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7819 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7820 7821 // get the new Points 7822 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7823 PetscInt b = points[2 * p]; 7824 PetscInt bDof = 0, bSecDof = 0, bOff; 7825 7826 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7827 if (!bSecDof) continue; 7828 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7829 if (bDof) { 7830 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7831 for (PetscInt q = 0; q < bDof; q++) { 7832 PetscInt a = anchors[bOff + q], aDof = 0; 7833 7834 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7835 if (aDof) { 7836 newPoints[2 * newP] = a; 7837 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7838 newP++; 7839 } 7840 } 7841 } else { 7842 newPoints[2 * newP] = b; 7843 newPoints[2 * newP + 1] = points[2 * p + 1]; 7844 newP++; 7845 } 7846 } 7847 7848 if (outMat) { 7849 PetscScalar *tmpMat; 7850 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7851 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7852 7853 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7854 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7855 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7856 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7857 7858 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7859 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7860 7861 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7862 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7863 7864 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7865 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7866 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7867 // for each field, insert the anchor modification into modMat 7868 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7869 PetscInt fStart = oldOffsets[f]; 7870 PetscInt fNewStart = newOffsets[f]; 7871 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7872 PetscInt b = points[2 * p]; 7873 PetscInt bDof = 0, bSecDof = 0, bOff; 7874 7875 if (b >= sStart && b < sEnd) { 7876 if (numFields) { 7877 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7878 } else { 7879 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7880 } 7881 } 7882 if (!bSecDof) continue; 7883 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7884 if (bDof) { 7885 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7886 for (PetscInt q = 0; q < bDof; q++, newP++) { 7887 PetscInt a = anchors[bOff + q], aDof = 0; 7888 7889 if (a >= sStart && a < sEnd) { 7890 if (numFields) { 7891 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7892 } else { 7893 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7894 } 7895 } 7896 if (aDof) { 7897 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7898 for (PetscInt d = 0; d < bSecDof; d++) { 7899 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7900 } 7901 } 7902 oNew += aDof; 7903 } 7904 } else { 7905 // Insert the identity matrix in this block 7906 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7907 oNew += bSecDof; 7908 newP++; 7909 } 7910 o += bSecDof; 7911 } 7912 } 7913 7914 *outMat = modMat; 7915 7916 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7917 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7918 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7919 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7920 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7921 } 7922 PetscCall(ISRestoreIndices(aIS, &anchors)); 7923 7924 /* output */ 7925 if (outPoints) { 7926 *outPoints = newPoints; 7927 } else { 7928 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7929 } 7930 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7931 PetscFunctionReturn(PETSC_SUCCESS); 7932 } 7933 7934 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) 7935 { 7936 PetscScalar *modMat = NULL; 7937 PetscInt newNumIndices = -1; 7938 7939 PetscFunctionBegin; 7940 /* 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. 7941 modMat is that matrix C */ 7942 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7943 if (outNumIndices) *outNumIndices = newNumIndices; 7944 if (modMat) { 7945 const PetscScalar *newValues = values; 7946 7947 if (multiplyRight) { 7948 PetscScalar *newNewValues = NULL; 7949 PetscBLASInt M, N, K; 7950 PetscScalar a = 1.0, b = 0.0; 7951 7952 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); 7953 7954 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7955 PetscCall(PetscBLASIntCast(numRows, &N)); 7956 PetscCall(PetscBLASIntCast(numIndices, &K)); 7957 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7958 // row-major to column-major conversion, right multiplication becomes left multiplication 7959 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7960 numCols = newNumIndices; 7961 newValues = newNewValues; 7962 } 7963 7964 if (multiplyLeft) { 7965 PetscScalar *newNewValues = NULL; 7966 PetscBLASInt M, N, K; 7967 PetscScalar a = 1.0, b = 0.0; 7968 7969 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); 7970 7971 PetscCall(PetscBLASIntCast(numCols, &M)); 7972 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7973 PetscCall(PetscBLASIntCast(numIndices, &K)); 7974 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7975 // row-major to column-major conversion, left multiplication becomes right multiplication 7976 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7977 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7978 newValues = newNewValues; 7979 } 7980 *outValues = (PetscScalar *)newValues; 7981 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7982 } 7983 PetscFunctionReturn(PETSC_SUCCESS); 7984 } 7985 7986 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) 7987 { 7988 PetscFunctionBegin; 7989 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7990 PetscFunctionReturn(PETSC_SUCCESS); 7991 } 7992 7993 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7994 { 7995 /* Closure ordering */ 7996 PetscSection clSection; 7997 IS clPoints; 7998 const PetscInt *clp; 7999 PetscInt *points; 8000 PetscInt Ncl, Ni = 0; 8001 8002 PetscFunctionBeginHot; 8003 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8004 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 8005 PetscInt dof; 8006 8007 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8008 Ni += dof; 8009 } 8010 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8011 *closureSize = Ni; 8012 PetscFunctionReturn(PETSC_SUCCESS); 8013 } 8014 8015 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) 8016 { 8017 /* Closure ordering */ 8018 PetscSection clSection; 8019 IS clPoints; 8020 const PetscInt *clp; 8021 PetscInt *points; 8022 const PetscInt *clperm = NULL; 8023 /* Dof permutation and sign flips */ 8024 const PetscInt **perms[32] = {NULL}; 8025 const PetscScalar **flips[32] = {NULL}; 8026 PetscScalar *valCopy = NULL; 8027 /* Hanging node constraints */ 8028 PetscInt *pointsC = NULL; 8029 PetscScalar *valuesC = NULL; 8030 PetscInt NclC, NiC; 8031 8032 PetscInt *idx; 8033 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8034 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8035 PetscInt idxStart, idxEnd; 8036 PetscInt nRows, nCols; 8037 8038 PetscFunctionBeginHot; 8039 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8040 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8041 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8042 PetscAssertPointer(numRows, 6); 8043 PetscAssertPointer(numCols, 7); 8044 if (indices) PetscAssertPointer(indices, 8); 8045 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8046 if (values) PetscAssertPointer(values, 10); 8047 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8048 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8049 PetscCall(PetscArrayzero(offsets, 32)); 8050 /* 1) Get points in closure */ 8051 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8052 if (useClPerm) { 8053 PetscInt depth, clsize; 8054 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8055 for (clsize = 0, p = 0; p < Ncl; p++) { 8056 PetscInt dof; 8057 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8058 clsize += dof; 8059 } 8060 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8061 } 8062 /* 2) Get number of indices on these points and field offsets from section */ 8063 for (p = 0; p < Ncl * 2; p += 2) { 8064 PetscInt dof, fdof; 8065 8066 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8067 for (f = 0; f < Nf; ++f) { 8068 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8069 offsets[f + 1] += fdof; 8070 } 8071 Ni += dof; 8072 } 8073 if (*numRows == -1) *numRows = Ni; 8074 if (*numCols == -1) *numCols = Ni; 8075 nRows = *numRows; 8076 nCols = *numCols; 8077 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8078 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8079 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8080 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8081 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8082 for (f = 0; f < PetscMax(1, Nf); ++f) { 8083 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8084 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8085 /* may need to apply sign changes to the element matrix */ 8086 if (values && flips[f]) { 8087 PetscInt foffset = offsets[f]; 8088 8089 for (p = 0; p < Ncl; ++p) { 8090 PetscInt pnt = points[2 * p], fdof; 8091 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8092 8093 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8094 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8095 if (flip) { 8096 PetscInt i, j, k; 8097 8098 if (!valCopy) { 8099 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8100 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8101 *values = valCopy; 8102 } 8103 for (i = 0; i < fdof; ++i) { 8104 PetscScalar fval = flip[i]; 8105 8106 if (multiplyRight) { 8107 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8108 } 8109 if (multiplyLeft) { 8110 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8111 } 8112 } 8113 } 8114 foffset += fdof; 8115 } 8116 } 8117 } 8118 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8119 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8120 if (NclC) { 8121 if (multiplyRight) *numCols = NiC; 8122 if (multiplyLeft) *numRows = NiC; 8123 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8124 for (f = 0; f < PetscMax(1, Nf); ++f) { 8125 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8126 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8127 } 8128 for (f = 0; f < PetscMax(1, Nf); ++f) { 8129 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8130 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8131 } 8132 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8133 Ncl = NclC; 8134 Ni = NiC; 8135 points = pointsC; 8136 if (values) *values = valuesC; 8137 } 8138 /* 5) Calculate indices */ 8139 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8140 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8141 if (Nf) { 8142 PetscInt idxOff; 8143 PetscBool useFieldOffsets; 8144 8145 if (outOffsets) { 8146 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8147 } 8148 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8149 if (useFieldOffsets) { 8150 for (p = 0; p < Ncl; ++p) { 8151 const PetscInt pnt = points[p * 2]; 8152 8153 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8154 } 8155 } else { 8156 for (p = 0; p < Ncl; ++p) { 8157 const PetscInt pnt = points[p * 2]; 8158 8159 if (pnt < idxStart || pnt >= idxEnd) continue; 8160 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8161 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8162 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8163 * global section. */ 8164 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8165 } 8166 } 8167 } else { 8168 PetscInt off = 0, idxOff; 8169 8170 for (p = 0; p < Ncl; ++p) { 8171 const PetscInt pnt = points[p * 2]; 8172 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8173 8174 if (pnt < idxStart || pnt >= idxEnd) continue; 8175 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8176 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8177 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8178 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8179 } 8180 } 8181 /* 6) Cleanup */ 8182 for (f = 0; f < PetscMax(1, Nf); ++f) { 8183 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8184 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8185 } 8186 if (NclC) { 8187 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8188 } else { 8189 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8190 } 8191 8192 if (indices) *indices = idx; 8193 PetscFunctionReturn(PETSC_SUCCESS); 8194 } 8195 8196 /*@C 8197 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8198 8199 Not collective 8200 8201 Input Parameters: 8202 + dm - The `DM` 8203 . section - The `PetscSection` describing the points (a local section) 8204 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8205 . point - The point defining the closure 8206 - useClPerm - Use the closure point permutation if available 8207 8208 Output Parameters: 8209 + numIndices - The number of dof indices in the closure of point with the input sections 8210 . indices - The dof indices 8211 . outOffsets - Array to write the field offsets into, or `NULL` 8212 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8213 8214 Level: advanced 8215 8216 Notes: 8217 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8218 8219 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8220 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8221 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8222 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8223 indices (with the above semantics) are implied. 8224 8225 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8226 `PetscSection`, `DMGetGlobalSection()` 8227 @*/ 8228 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8229 { 8230 PetscInt numRows = -1, numCols = -1; 8231 8232 PetscFunctionBeginHot; 8233 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8234 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8235 *numIndices = numRows; 8236 PetscFunctionReturn(PETSC_SUCCESS); 8237 } 8238 8239 /*@C 8240 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8241 8242 Not collective 8243 8244 Input Parameters: 8245 + dm - The `DM` 8246 . section - The `PetscSection` describing the points (a local section) 8247 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8248 . point - The point defining the closure 8249 - useClPerm - Use the closure point permutation if available 8250 8251 Output Parameters: 8252 + numIndices - The number of dof indices in the closure of point with the input sections 8253 . indices - The dof indices 8254 . outOffsets - Array to write the field offsets into, or `NULL` 8255 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8256 8257 Level: advanced 8258 8259 Notes: 8260 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8261 8262 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8263 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8264 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8265 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8266 indices (with the above semantics) are implied. 8267 8268 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8269 @*/ 8270 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8271 { 8272 PetscFunctionBegin; 8273 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8274 PetscAssertPointer(indices, 7); 8275 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8276 PetscFunctionReturn(PETSC_SUCCESS); 8277 } 8278 8279 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8280 { 8281 DM_Plex *mesh = (DM_Plex *)dm->data; 8282 PetscInt *indices; 8283 PetscInt numIndices; 8284 const PetscScalar *valuesOrig = values; 8285 PetscErrorCode ierr; 8286 8287 PetscFunctionBegin; 8288 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8289 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8290 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8291 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8292 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8293 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8294 8295 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8296 8297 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8298 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8299 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8300 if (ierr) { 8301 PetscMPIInt rank; 8302 8303 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8304 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8305 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8306 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8307 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8308 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8309 } 8310 if (mesh->printFEM > 1) { 8311 PetscInt i; 8312 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8313 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8314 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8315 } 8316 8317 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8318 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8319 PetscFunctionReturn(PETSC_SUCCESS); 8320 } 8321 8322 /*@C 8323 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8324 8325 Not collective 8326 8327 Input Parameters: 8328 + dm - The `DM` 8329 . section - The section describing the layout in `v`, or `NULL` to use the default section 8330 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8331 . A - The matrix 8332 . point - The point in the `DM` 8333 . values - The array of values 8334 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8335 8336 Level: intermediate 8337 8338 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8339 @*/ 8340 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8341 { 8342 PetscFunctionBegin; 8343 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8344 PetscFunctionReturn(PETSC_SUCCESS); 8345 } 8346 8347 /*@C 8348 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8349 8350 Not collective 8351 8352 Input Parameters: 8353 + dmRow - The `DM` for the row fields 8354 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8355 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8356 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8357 . dmCol - The `DM` for the column fields 8358 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8359 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8360 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8361 . A - The matrix 8362 . point - The point in the `DM` 8363 . values - The array of values 8364 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8365 8366 Level: intermediate 8367 8368 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8369 @*/ 8370 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) 8371 { 8372 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8373 PetscInt *indicesRow, *indicesCol; 8374 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8375 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8376 8377 PetscErrorCode ierr; 8378 8379 PetscFunctionBegin; 8380 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8381 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8382 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8383 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8384 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8385 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8386 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8387 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8388 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8389 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8390 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8391 8392 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8393 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8394 valuesV1 = valuesV0; 8395 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8396 valuesV2 = valuesV1; 8397 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8398 8399 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8400 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8401 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8402 if (ierr) { 8403 PetscMPIInt rank; 8404 8405 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8406 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8407 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8408 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8409 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8410 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8411 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8412 } 8413 8414 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8415 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8416 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8417 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8418 PetscFunctionReturn(PETSC_SUCCESS); 8419 } 8420 8421 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8422 { 8423 DM_Plex *mesh = (DM_Plex *)dmf->data; 8424 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8425 PetscInt *cpoints = NULL; 8426 PetscInt *findices, *cindices; 8427 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8428 PetscInt foffsets[32], coffsets[32]; 8429 DMPolytopeType ct; 8430 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8431 PetscErrorCode ierr; 8432 8433 PetscFunctionBegin; 8434 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8435 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8436 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8437 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8438 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8439 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8440 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8441 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8442 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8443 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8444 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8445 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8446 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8447 PetscCall(PetscArrayzero(foffsets, 32)); 8448 PetscCall(PetscArrayzero(coffsets, 32)); 8449 /* Column indices */ 8450 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8451 maxFPoints = numCPoints; 8452 /* Compress out points not in the section */ 8453 /* TODO: Squeeze out points with 0 dof as well */ 8454 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8455 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8456 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8457 cpoints[q * 2] = cpoints[p]; 8458 cpoints[q * 2 + 1] = cpoints[p + 1]; 8459 ++q; 8460 } 8461 } 8462 numCPoints = q; 8463 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8464 PetscInt fdof; 8465 8466 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8467 if (!dof) continue; 8468 for (f = 0; f < numFields; ++f) { 8469 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8470 coffsets[f + 1] += fdof; 8471 } 8472 numCIndices += dof; 8473 } 8474 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8475 /* Row indices */ 8476 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8477 { 8478 DMPlexTransform tr; 8479 DMPolytopeType *rct; 8480 PetscInt *rsize, *rcone, *rornt, Nt; 8481 8482 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8483 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8484 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8485 numSubcells = rsize[Nt - 1]; 8486 PetscCall(DMPlexTransformDestroy(&tr)); 8487 } 8488 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8489 for (r = 0, q = 0; r < numSubcells; ++r) { 8490 /* TODO Map from coarse to fine cells */ 8491 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8492 /* Compress out points not in the section */ 8493 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8494 for (p = 0; p < numFPoints * 2; p += 2) { 8495 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8496 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8497 if (!dof) continue; 8498 for (s = 0; s < q; ++s) 8499 if (fpoints[p] == ftotpoints[s * 2]) break; 8500 if (s < q) continue; 8501 ftotpoints[q * 2] = fpoints[p]; 8502 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8503 ++q; 8504 } 8505 } 8506 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8507 } 8508 numFPoints = q; 8509 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8510 PetscInt fdof; 8511 8512 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8513 if (!dof) continue; 8514 for (f = 0; f < numFields; ++f) { 8515 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8516 foffsets[f + 1] += fdof; 8517 } 8518 numFIndices += dof; 8519 } 8520 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8521 8522 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8523 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8524 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8525 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8526 if (numFields) { 8527 const PetscInt **permsF[32] = {NULL}; 8528 const PetscInt **permsC[32] = {NULL}; 8529 8530 for (f = 0; f < numFields; f++) { 8531 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8532 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8533 } 8534 for (p = 0; p < numFPoints; p++) { 8535 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8536 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8537 } 8538 for (p = 0; p < numCPoints; p++) { 8539 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8540 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8541 } 8542 for (f = 0; f < numFields; f++) { 8543 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8544 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8545 } 8546 } else { 8547 const PetscInt **permsF = NULL; 8548 const PetscInt **permsC = NULL; 8549 8550 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8551 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8552 for (p = 0, off = 0; p < numFPoints; p++) { 8553 const PetscInt *perm = permsF ? permsF[p] : NULL; 8554 8555 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8556 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8557 } 8558 for (p = 0, off = 0; p < numCPoints; p++) { 8559 const PetscInt *perm = permsC ? permsC[p] : NULL; 8560 8561 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8562 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8563 } 8564 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8565 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8566 } 8567 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8568 /* TODO: flips */ 8569 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8570 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8571 if (ierr) { 8572 PetscMPIInt rank; 8573 8574 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8575 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8576 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8577 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8578 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8579 } 8580 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8581 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8582 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8583 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8584 PetscFunctionReturn(PETSC_SUCCESS); 8585 } 8586 8587 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8588 { 8589 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8590 PetscInt *cpoints = NULL; 8591 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8592 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8593 DMPolytopeType ct; 8594 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8595 8596 PetscFunctionBegin; 8597 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8598 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8599 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8600 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8601 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8602 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8603 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8604 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8605 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8606 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8607 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8608 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8609 /* Column indices */ 8610 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8611 maxFPoints = numCPoints; 8612 /* Compress out points not in the section */ 8613 /* TODO: Squeeze out points with 0 dof as well */ 8614 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8615 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8616 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8617 cpoints[q * 2] = cpoints[p]; 8618 cpoints[q * 2 + 1] = cpoints[p + 1]; 8619 ++q; 8620 } 8621 } 8622 numCPoints = q; 8623 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8624 PetscInt fdof; 8625 8626 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8627 if (!dof) continue; 8628 for (f = 0; f < numFields; ++f) { 8629 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8630 coffsets[f + 1] += fdof; 8631 } 8632 numCIndices += dof; 8633 } 8634 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8635 /* Row indices */ 8636 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8637 { 8638 DMPlexTransform tr; 8639 DMPolytopeType *rct; 8640 PetscInt *rsize, *rcone, *rornt, Nt; 8641 8642 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8643 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8644 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8645 numSubcells = rsize[Nt - 1]; 8646 PetscCall(DMPlexTransformDestroy(&tr)); 8647 } 8648 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8649 for (r = 0, q = 0; r < numSubcells; ++r) { 8650 /* TODO Map from coarse to fine cells */ 8651 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8652 /* Compress out points not in the section */ 8653 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8654 for (p = 0; p < numFPoints * 2; p += 2) { 8655 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8656 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8657 if (!dof) continue; 8658 for (s = 0; s < q; ++s) 8659 if (fpoints[p] == ftotpoints[s * 2]) break; 8660 if (s < q) continue; 8661 ftotpoints[q * 2] = fpoints[p]; 8662 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8663 ++q; 8664 } 8665 } 8666 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8667 } 8668 numFPoints = q; 8669 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8670 PetscInt fdof; 8671 8672 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8673 if (!dof) continue; 8674 for (f = 0; f < numFields; ++f) { 8675 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8676 foffsets[f + 1] += fdof; 8677 } 8678 numFIndices += dof; 8679 } 8680 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8681 8682 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8683 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8684 if (numFields) { 8685 const PetscInt **permsF[32] = {NULL}; 8686 const PetscInt **permsC[32] = {NULL}; 8687 8688 for (f = 0; f < numFields; f++) { 8689 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8690 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8691 } 8692 for (p = 0; p < numFPoints; p++) { 8693 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8694 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8695 } 8696 for (p = 0; p < numCPoints; p++) { 8697 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8698 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8699 } 8700 for (f = 0; f < numFields; f++) { 8701 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8702 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8703 } 8704 } else { 8705 const PetscInt **permsF = NULL; 8706 const PetscInt **permsC = NULL; 8707 8708 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8709 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8710 for (p = 0, off = 0; p < numFPoints; p++) { 8711 const PetscInt *perm = permsF ? permsF[p] : NULL; 8712 8713 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8714 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8715 } 8716 for (p = 0, off = 0; p < numCPoints; p++) { 8717 const PetscInt *perm = permsC ? permsC[p] : NULL; 8718 8719 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8720 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8721 } 8722 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8723 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8724 } 8725 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8726 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8727 PetscFunctionReturn(PETSC_SUCCESS); 8728 } 8729 8730 /*@ 8731 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8732 8733 Input Parameter: 8734 . dm - The `DMPLEX` object 8735 8736 Output Parameter: 8737 . cellHeight - The height of a cell 8738 8739 Level: developer 8740 8741 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8742 @*/ 8743 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8744 { 8745 DM_Plex *mesh = (DM_Plex *)dm->data; 8746 8747 PetscFunctionBegin; 8748 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8749 PetscAssertPointer(cellHeight, 2); 8750 *cellHeight = mesh->vtkCellHeight; 8751 PetscFunctionReturn(PETSC_SUCCESS); 8752 } 8753 8754 /*@ 8755 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8756 8757 Input Parameters: 8758 + dm - The `DMPLEX` object 8759 - cellHeight - The height of a cell 8760 8761 Level: developer 8762 8763 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8764 @*/ 8765 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8766 { 8767 DM_Plex *mesh = (DM_Plex *)dm->data; 8768 8769 PetscFunctionBegin; 8770 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8771 mesh->vtkCellHeight = cellHeight; 8772 PetscFunctionReturn(PETSC_SUCCESS); 8773 } 8774 8775 /*@ 8776 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8777 8778 Input Parameters: 8779 + dm - The `DMPLEX` object 8780 - ct - The `DMPolytopeType` of the cell 8781 8782 Output Parameters: 8783 + start - The first cell of this type, or `NULL` 8784 - end - The upper bound on this celltype, or `NULL` 8785 8786 Level: advanced 8787 8788 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8789 @*/ 8790 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end) 8791 { 8792 DM_Plex *mesh = (DM_Plex *)dm->data; 8793 DMLabel label; 8794 PetscInt pStart, pEnd; 8795 8796 PetscFunctionBegin; 8797 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8798 if (start) { 8799 PetscAssertPointer(start, 3); 8800 *start = 0; 8801 } 8802 if (end) { 8803 PetscAssertPointer(end, 4); 8804 *end = 0; 8805 } 8806 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8807 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8808 if (mesh->tr) { 8809 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8810 } else { 8811 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8812 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8813 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8814 } 8815 PetscFunctionReturn(PETSC_SUCCESS); 8816 } 8817 8818 /*@ 8819 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8820 8821 Input Parameters: 8822 + dm - The `DMPLEX` object 8823 - depth - The depth for the given point stratum 8824 8825 Output Parameter: 8826 . gsize - The global number of points in the stratum 8827 8828 Level: advanced 8829 8830 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8831 @*/ 8832 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8833 { 8834 PetscSF sf; 8835 const PetscInt *leaves; 8836 PetscInt Nl, loc, start, end, lsize = 0; 8837 8838 PetscFunctionBegin; 8839 PetscCall(DMGetPointSF(dm, &sf)); 8840 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8841 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8842 for (PetscInt p = start; p < end; ++p) { 8843 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8844 if (loc < 0) ++lsize; 8845 } 8846 PetscCallMPI(MPI_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8847 PetscFunctionReturn(PETSC_SUCCESS); 8848 } 8849 8850 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8851 { 8852 PetscSection section, globalSection; 8853 PetscInt *numbers, p; 8854 8855 PetscFunctionBegin; 8856 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8857 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8858 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8859 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8860 PetscCall(PetscSectionSetUp(section)); 8861 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8862 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8863 for (p = pStart; p < pEnd; ++p) { 8864 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8865 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8866 else numbers[p - pStart] += shift; 8867 } 8868 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8869 if (globalSize) { 8870 PetscLayout layout; 8871 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8872 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8873 PetscCall(PetscLayoutDestroy(&layout)); 8874 } 8875 PetscCall(PetscSectionDestroy(§ion)); 8876 PetscCall(PetscSectionDestroy(&globalSection)); 8877 PetscFunctionReturn(PETSC_SUCCESS); 8878 } 8879 8880 /*@ 8881 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8882 8883 Input Parameters: 8884 + dm - The `DMPLEX` object 8885 - includeAll - Whether to include all cells, or just the simplex and box cells 8886 8887 Output Parameter: 8888 . globalCellNumbers - Global cell numbers for all cells on this process 8889 8890 Level: developer 8891 8892 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8893 @*/ 8894 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8895 { 8896 PetscInt cellHeight, cStart, cEnd; 8897 8898 PetscFunctionBegin; 8899 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8900 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8901 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8902 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8903 PetscFunctionReturn(PETSC_SUCCESS); 8904 } 8905 8906 /*@ 8907 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8908 8909 Input Parameter: 8910 . dm - The `DMPLEX` object 8911 8912 Output Parameter: 8913 . globalCellNumbers - Global cell numbers for all cells on this process 8914 8915 Level: developer 8916 8917 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8918 @*/ 8919 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8920 { 8921 DM_Plex *mesh = (DM_Plex *)dm->data; 8922 8923 PetscFunctionBegin; 8924 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8925 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8926 *globalCellNumbers = mesh->globalCellNumbers; 8927 PetscFunctionReturn(PETSC_SUCCESS); 8928 } 8929 8930 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8931 { 8932 PetscInt vStart, vEnd; 8933 8934 PetscFunctionBegin; 8935 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8936 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8937 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8938 PetscFunctionReturn(PETSC_SUCCESS); 8939 } 8940 8941 /*@ 8942 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8943 8944 Input Parameter: 8945 . dm - The `DMPLEX` object 8946 8947 Output Parameter: 8948 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8949 8950 Level: developer 8951 8952 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8953 @*/ 8954 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8955 { 8956 DM_Plex *mesh = (DM_Plex *)dm->data; 8957 8958 PetscFunctionBegin; 8959 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8960 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8961 *globalVertexNumbers = mesh->globalVertexNumbers; 8962 PetscFunctionReturn(PETSC_SUCCESS); 8963 } 8964 8965 /*@ 8966 DMPlexCreatePointNumbering - Create a global numbering for all points. 8967 8968 Collective 8969 8970 Input Parameter: 8971 . dm - The `DMPLEX` object 8972 8973 Output Parameter: 8974 . globalPointNumbers - Global numbers for all points on this process 8975 8976 Level: developer 8977 8978 Notes: 8979 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8980 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8981 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8982 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8983 8984 The partitioned mesh is 8985 ``` 8986 (2)--0--(3)--1--(4) (1)--0--(2) 8987 ``` 8988 and its global numbering is 8989 ``` 8990 (3)--0--(4)--1--(5)--2--(6) 8991 ``` 8992 Then the global numbering is provided as 8993 ``` 8994 [0] Number of indices in set 5 8995 [0] 0 0 8996 [0] 1 1 8997 [0] 2 3 8998 [0] 3 4 8999 [0] 4 -6 9000 [1] Number of indices in set 3 9001 [1] 0 2 9002 [1] 1 5 9003 [1] 2 6 9004 ``` 9005 9006 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9007 @*/ 9008 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 9009 { 9010 IS nums[4]; 9011 PetscInt depths[4], gdepths[4], starts[4]; 9012 PetscInt depth, d, shift = 0; 9013 PetscBool empty = PETSC_FALSE; 9014 9015 PetscFunctionBegin; 9016 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9017 PetscCall(DMPlexGetDepth(dm, &depth)); 9018 // For unstratified meshes use dim instead of depth 9019 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9020 // If any stratum is empty, we must mark all empty 9021 for (d = 0; d <= depth; ++d) { 9022 PetscInt end; 9023 9024 depths[d] = depth - d; 9025 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9026 if (!(starts[d] - end)) empty = PETSC_TRUE; 9027 } 9028 if (empty) 9029 for (d = 0; d <= depth; ++d) { 9030 depths[d] = -1; 9031 starts[d] = -1; 9032 } 9033 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9034 PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9035 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]); 9036 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9037 for (d = 0; d <= depth; ++d) { 9038 PetscInt pStart, pEnd, gsize; 9039 9040 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9041 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9042 shift += gsize; 9043 } 9044 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9045 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9046 PetscFunctionReturn(PETSC_SUCCESS); 9047 } 9048 9049 /*@ 9050 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9051 9052 Collective 9053 9054 Input Parameter: 9055 . dm - The `DMPLEX` object 9056 9057 Output Parameter: 9058 . globalEdgeNumbers - Global numbers for all edges on this process 9059 9060 Level: developer 9061 9062 Notes: 9063 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). 9064 9065 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9066 @*/ 9067 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9068 { 9069 PetscSF sf; 9070 PetscInt eStart, eEnd; 9071 9072 PetscFunctionBegin; 9073 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9074 PetscCall(DMGetPointSF(dm, &sf)); 9075 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9076 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9077 PetscFunctionReturn(PETSC_SUCCESS); 9078 } 9079 9080 /*@ 9081 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9082 9083 Input Parameter: 9084 . dm - The `DMPLEX` object 9085 9086 Output Parameter: 9087 . ranks - The rank field 9088 9089 Options Database Key: 9090 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9091 9092 Level: intermediate 9093 9094 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9095 @*/ 9096 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9097 { 9098 DM rdm; 9099 PetscFE fe; 9100 PetscScalar *r; 9101 PetscMPIInt rank; 9102 DMPolytopeType ct; 9103 PetscInt dim, cStart, cEnd, c; 9104 PetscBool simplex; 9105 9106 PetscFunctionBeginUser; 9107 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9108 PetscAssertPointer(ranks, 2); 9109 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9110 PetscCall(DMClone(dm, &rdm)); 9111 PetscCall(DMGetDimension(rdm, &dim)); 9112 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9113 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9114 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9115 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9116 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9117 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9118 PetscCall(PetscFEDestroy(&fe)); 9119 PetscCall(DMCreateDS(rdm)); 9120 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9121 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9122 PetscCall(VecGetArray(*ranks, &r)); 9123 for (c = cStart; c < cEnd; ++c) { 9124 PetscScalar *lr; 9125 9126 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9127 if (lr) *lr = rank; 9128 } 9129 PetscCall(VecRestoreArray(*ranks, &r)); 9130 PetscCall(DMDestroy(&rdm)); 9131 PetscFunctionReturn(PETSC_SUCCESS); 9132 } 9133 9134 /*@ 9135 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9136 9137 Input Parameters: 9138 + dm - The `DMPLEX` 9139 - label - The `DMLabel` 9140 9141 Output Parameter: 9142 . val - The label value field 9143 9144 Options Database Key: 9145 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9146 9147 Level: intermediate 9148 9149 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9150 @*/ 9151 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9152 { 9153 DM rdm, plex; 9154 Vec lval; 9155 PetscSection section; 9156 PetscFE fe; 9157 PetscScalar *v; 9158 PetscInt dim, pStart, pEnd, p, cStart; 9159 DMPolytopeType ct; 9160 char name[PETSC_MAX_PATH_LEN]; 9161 const char *lname, *prefix; 9162 9163 PetscFunctionBeginUser; 9164 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9165 PetscAssertPointer(label, 2); 9166 PetscAssertPointer(val, 3); 9167 PetscCall(DMClone(dm, &rdm)); 9168 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9169 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9170 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9171 PetscCall(DMDestroy(&plex)); 9172 PetscCall(DMGetDimension(rdm, &dim)); 9173 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9174 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9175 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9176 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9177 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9178 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9179 PetscCall(PetscFEDestroy(&fe)); 9180 PetscCall(DMCreateDS(rdm)); 9181 PetscCall(DMCreateGlobalVector(rdm, val)); 9182 PetscCall(DMCreateLocalVector(rdm, &lval)); 9183 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9184 PetscCall(DMGetLocalSection(rdm, §ion)); 9185 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9186 PetscCall(VecGetArray(lval, &v)); 9187 for (p = pStart; p < pEnd; ++p) { 9188 PetscInt cval, dof, off; 9189 9190 PetscCall(PetscSectionGetDof(section, p, &dof)); 9191 if (!dof) continue; 9192 PetscCall(DMLabelGetValue(label, p, &cval)); 9193 PetscCall(PetscSectionGetOffset(section, p, &off)); 9194 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9195 } 9196 PetscCall(VecRestoreArray(lval, &v)); 9197 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9198 PetscCall(VecDestroy(&lval)); 9199 PetscCall(DMDestroy(&rdm)); 9200 PetscFunctionReturn(PETSC_SUCCESS); 9201 } 9202 9203 /*@ 9204 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9205 9206 Input Parameter: 9207 . dm - The `DMPLEX` object 9208 9209 Level: developer 9210 9211 Notes: 9212 This is a useful diagnostic when creating meshes programmatically. 9213 9214 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9215 9216 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9217 @*/ 9218 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9219 { 9220 PetscSection coneSection, supportSection; 9221 const PetscInt *cone, *support; 9222 PetscInt coneSize, c, supportSize, s; 9223 PetscInt pStart, pEnd, p, pp, csize, ssize; 9224 PetscBool storagecheck = PETSC_TRUE; 9225 9226 PetscFunctionBegin; 9227 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9228 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9229 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9230 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9231 /* Check that point p is found in the support of its cone points, and vice versa */ 9232 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9233 for (p = pStart; p < pEnd; ++p) { 9234 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9235 PetscCall(DMPlexGetCone(dm, p, &cone)); 9236 for (c = 0; c < coneSize; ++c) { 9237 PetscBool dup = PETSC_FALSE; 9238 PetscInt d; 9239 for (d = c - 1; d >= 0; --d) { 9240 if (cone[c] == cone[d]) { 9241 dup = PETSC_TRUE; 9242 break; 9243 } 9244 } 9245 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9246 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9247 for (s = 0; s < supportSize; ++s) { 9248 if (support[s] == p) break; 9249 } 9250 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9251 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9252 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9253 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9254 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9255 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9256 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9257 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]); 9258 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9259 } 9260 } 9261 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9262 if (p != pp) { 9263 storagecheck = PETSC_FALSE; 9264 continue; 9265 } 9266 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9267 PetscCall(DMPlexGetSupport(dm, p, &support)); 9268 for (s = 0; s < supportSize; ++s) { 9269 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9270 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9271 for (c = 0; c < coneSize; ++c) { 9272 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9273 if (cone[c] != pp) { 9274 c = 0; 9275 break; 9276 } 9277 if (cone[c] == p) break; 9278 } 9279 if (c >= coneSize) { 9280 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9281 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9282 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9283 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9284 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9285 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9286 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9287 } 9288 } 9289 } 9290 if (storagecheck) { 9291 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9292 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9293 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9294 } 9295 PetscFunctionReturn(PETSC_SUCCESS); 9296 } 9297 9298 /* 9299 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. 9300 */ 9301 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9302 { 9303 DMPolytopeType cct; 9304 PetscInt ptpoints[4]; 9305 const PetscInt *cone, *ccone, *ptcone; 9306 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9307 9308 PetscFunctionBegin; 9309 *unsplit = 0; 9310 switch (ct) { 9311 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9312 ptpoints[npt++] = c; 9313 break; 9314 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9315 PetscCall(DMPlexGetCone(dm, c, &cone)); 9316 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9317 for (cp = 0; cp < coneSize; ++cp) { 9318 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9319 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9320 } 9321 break; 9322 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9323 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9324 PetscCall(DMPlexGetCone(dm, c, &cone)); 9325 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9326 for (cp = 0; cp < coneSize; ++cp) { 9327 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9328 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9329 for (ccp = 0; ccp < cconeSize; ++ccp) { 9330 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9331 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9332 PetscInt p; 9333 for (p = 0; p < npt; ++p) 9334 if (ptpoints[p] == ccone[ccp]) break; 9335 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9336 } 9337 } 9338 } 9339 break; 9340 default: 9341 break; 9342 } 9343 for (pt = 0; pt < npt; ++pt) { 9344 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9345 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9346 } 9347 PetscFunctionReturn(PETSC_SUCCESS); 9348 } 9349 9350 /*@ 9351 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9352 9353 Input Parameters: 9354 + dm - The `DMPLEX` object 9355 - cellHeight - Normally 0 9356 9357 Level: developer 9358 9359 Notes: 9360 This is a useful diagnostic when creating meshes programmatically. 9361 Currently applicable only to homogeneous simplex or tensor meshes. 9362 9363 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9364 9365 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9366 @*/ 9367 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9368 { 9369 DMPlexInterpolatedFlag interp; 9370 DMPolytopeType ct; 9371 PetscInt vStart, vEnd, cStart, cEnd, c; 9372 9373 PetscFunctionBegin; 9374 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9375 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9376 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9377 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9378 for (c = cStart; c < cEnd; ++c) { 9379 PetscInt *closure = NULL; 9380 PetscInt coneSize, closureSize, cl, Nv = 0; 9381 9382 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9383 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9384 if (interp == DMPLEX_INTERPOLATED_FULL) { 9385 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9386 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)); 9387 } 9388 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9389 for (cl = 0; cl < closureSize * 2; cl += 2) { 9390 const PetscInt p = closure[cl]; 9391 if ((p >= vStart) && (p < vEnd)) ++Nv; 9392 } 9393 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9394 /* Special Case: Tensor faces with identified vertices */ 9395 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9396 PetscInt unsplit; 9397 9398 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9399 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9400 } 9401 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)); 9402 } 9403 PetscFunctionReturn(PETSC_SUCCESS); 9404 } 9405 9406 /*@ 9407 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9408 9409 Collective 9410 9411 Input Parameters: 9412 + dm - The `DMPLEX` object 9413 - cellHeight - Normally 0 9414 9415 Level: developer 9416 9417 Notes: 9418 This is a useful diagnostic when creating meshes programmatically. 9419 This routine is only relevant for meshes that are fully interpolated across all ranks. 9420 It will error out if a partially interpolated mesh is given on some rank. 9421 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9422 9423 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9424 9425 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9426 @*/ 9427 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9428 { 9429 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9430 DMPlexInterpolatedFlag interpEnum; 9431 9432 PetscFunctionBegin; 9433 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9434 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9435 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9436 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9437 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9438 PetscFunctionReturn(PETSC_SUCCESS); 9439 } 9440 9441 PetscCall(DMGetDimension(dm, &dim)); 9442 PetscCall(DMPlexGetDepth(dm, &depth)); 9443 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9444 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9445 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9446 for (c = cStart; c < cEnd; ++c) { 9447 const PetscInt *cone, *ornt, *faceSizes, *faces; 9448 const DMPolytopeType *faceTypes; 9449 DMPolytopeType ct; 9450 PetscInt numFaces, coneSize, f; 9451 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9452 9453 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9454 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9455 if (unsplit) continue; 9456 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9457 PetscCall(DMPlexGetCone(dm, c, &cone)); 9458 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9459 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9460 for (cl = 0; cl < closureSize * 2; cl += 2) { 9461 const PetscInt p = closure[cl]; 9462 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9463 } 9464 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9465 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); 9466 for (f = 0; f < numFaces; ++f) { 9467 DMPolytopeType fct; 9468 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9469 9470 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9471 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9472 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9473 const PetscInt p = fclosure[cl]; 9474 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9475 } 9476 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]); 9477 for (v = 0; v < fnumCorners; ++v) { 9478 if (fclosure[v] != faces[fOff + v]) { 9479 PetscInt v1; 9480 9481 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9482 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9483 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9484 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9485 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9486 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]); 9487 } 9488 } 9489 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9490 fOff += faceSizes[f]; 9491 } 9492 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9493 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9494 } 9495 } 9496 PetscFunctionReturn(PETSC_SUCCESS); 9497 } 9498 9499 /*@ 9500 DMPlexCheckGeometry - Check the geometry of mesh cells 9501 9502 Input Parameter: 9503 . dm - The `DMPLEX` object 9504 9505 Level: developer 9506 9507 Notes: 9508 This is a useful diagnostic when creating meshes programmatically. 9509 9510 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9511 9512 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9513 @*/ 9514 PetscErrorCode DMPlexCheckGeometry(DM dm) 9515 { 9516 Vec coordinates; 9517 PetscReal detJ, J[9], refVol = 1.0; 9518 PetscReal vol; 9519 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9520 9521 PetscFunctionBegin; 9522 PetscCall(DMGetDimension(dm, &dim)); 9523 PetscCall(DMGetCoordinateDim(dm, &dE)); 9524 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9525 PetscCall(DMPlexGetDepth(dm, &depth)); 9526 for (d = 0; d < dim; ++d) refVol *= 2.0; 9527 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9528 /* Make sure local coordinates are created, because that step is collective */ 9529 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9530 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9531 for (c = cStart; c < cEnd; ++c) { 9532 DMPolytopeType ct; 9533 PetscInt unsplit; 9534 PetscBool ignoreZeroVol = PETSC_FALSE; 9535 9536 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9537 switch (ct) { 9538 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9539 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9540 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9541 ignoreZeroVol = PETSC_TRUE; 9542 break; 9543 default: 9544 break; 9545 } 9546 switch (ct) { 9547 case DM_POLYTOPE_TRI_PRISM: 9548 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9549 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9550 case DM_POLYTOPE_PYRAMID: 9551 continue; 9552 default: 9553 break; 9554 } 9555 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9556 if (unsplit) continue; 9557 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9558 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); 9559 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9560 /* This should work with periodicity since DG coordinates should be used */ 9561 if (depth > 1) { 9562 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9563 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); 9564 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9565 } 9566 } 9567 PetscFunctionReturn(PETSC_SUCCESS); 9568 } 9569 9570 /*@ 9571 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9572 9573 Collective 9574 9575 Input Parameters: 9576 + dm - The `DMPLEX` object 9577 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9578 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9579 9580 Level: developer 9581 9582 Notes: 9583 This is mainly intended for debugging/testing purposes. 9584 9585 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9586 9587 Extra roots can come from periodic cuts, where additional points appear on the boundary 9588 9589 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9590 @*/ 9591 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9592 { 9593 PetscInt l, nleaves, nroots, overlap; 9594 const PetscInt *locals; 9595 const PetscSFNode *remotes; 9596 PetscBool distributed; 9597 MPI_Comm comm; 9598 PetscMPIInt rank; 9599 9600 PetscFunctionBegin; 9601 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9602 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9603 else pointSF = dm->sf; 9604 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9605 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9606 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9607 { 9608 PetscMPIInt mpiFlag; 9609 9610 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9611 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9612 } 9613 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9614 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9615 if (!distributed) { 9616 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); 9617 PetscFunctionReturn(PETSC_SUCCESS); 9618 } 9619 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); 9620 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9621 9622 /* Check SF graph is compatible with DMPlex chart */ 9623 { 9624 PetscInt pStart, pEnd, maxLeaf; 9625 9626 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9627 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9628 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9629 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9630 } 9631 9632 /* Check Point SF has no local points referenced */ 9633 for (l = 0; l < nleaves; l++) { 9634 PetscMPIInt irank; 9635 9636 PetscCall(PetscMPIIntCast(remotes[l].rank, &irank)); 9637 PetscAssert(irank != rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%d,%" PetscInt_FMT ")", locals ? locals[l] : l, irank, remotes[l].index); 9638 } 9639 9640 /* Check there are no cells in interface */ 9641 if (!overlap) { 9642 PetscInt cellHeight, cStart, cEnd; 9643 9644 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9645 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9646 for (l = 0; l < nleaves; ++l) { 9647 const PetscInt point = locals ? locals[l] : l; 9648 9649 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9650 } 9651 } 9652 9653 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9654 { 9655 const PetscInt *rootdegree; 9656 9657 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9658 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9659 for (l = 0; l < nleaves; ++l) { 9660 const PetscInt point = locals ? locals[l] : l; 9661 const PetscInt *cone; 9662 PetscInt coneSize, c, idx; 9663 9664 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9665 PetscCall(DMPlexGetCone(dm, point, &cone)); 9666 for (c = 0; c < coneSize; ++c) { 9667 if (!rootdegree[cone[c]]) { 9668 if (locals) { 9669 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9670 } else { 9671 idx = (cone[c] < nleaves) ? cone[c] : -1; 9672 } 9673 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9674 } 9675 } 9676 } 9677 } 9678 PetscFunctionReturn(PETSC_SUCCESS); 9679 } 9680 9681 /*@ 9682 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9683 9684 Collective 9685 9686 Input Parameter: 9687 . dm - The `DMPLEX` object 9688 9689 Level: developer 9690 9691 Notes: 9692 This is mainly intended for debugging/testing purposes. 9693 9694 Other cell types which are disconnected would be caught by the symmetry and face checks. 9695 9696 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9697 9698 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9699 @*/ 9700 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9701 { 9702 PetscInt pStart, pEnd, vStart, vEnd; 9703 9704 PetscFunctionBegin; 9705 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9706 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9707 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9708 for (PetscInt v = vStart; v < vEnd; ++v) { 9709 PetscInt suppSize; 9710 9711 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9712 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9713 } 9714 PetscFunctionReturn(PETSC_SUCCESS); 9715 } 9716 9717 /*@ 9718 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9719 9720 Input Parameter: 9721 . dm - The `DMPLEX` object 9722 9723 Level: developer 9724 9725 Notes: 9726 This is a useful diagnostic when creating meshes programmatically. 9727 9728 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9729 9730 Currently does not include `DMPlexCheckCellShape()`. 9731 9732 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9733 @*/ 9734 PetscErrorCode DMPlexCheck(DM dm) 9735 { 9736 PetscInt cellHeight; 9737 9738 PetscFunctionBegin; 9739 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9740 PetscCall(DMPlexCheckSymmetry(dm)); 9741 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9742 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9743 PetscCall(DMPlexCheckGeometry(dm)); 9744 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9745 PetscCall(DMPlexCheckInterfaceCones(dm)); 9746 PetscCall(DMPlexCheckOrphanVertices(dm)); 9747 PetscFunctionReturn(PETSC_SUCCESS); 9748 } 9749 9750 typedef struct cell_stats { 9751 PetscReal min, max, sum, squaresum; 9752 PetscInt count; 9753 } cell_stats_t; 9754 9755 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9756 { 9757 PetscInt i, N = *len; 9758 9759 for (i = 0; i < N; i++) { 9760 cell_stats_t *A = (cell_stats_t *)a; 9761 cell_stats_t *B = (cell_stats_t *)b; 9762 9763 B->min = PetscMin(A->min, B->min); 9764 B->max = PetscMax(A->max, B->max); 9765 B->sum += A->sum; 9766 B->squaresum += A->squaresum; 9767 B->count += A->count; 9768 } 9769 } 9770 9771 /*@ 9772 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9773 9774 Collective 9775 9776 Input Parameters: 9777 + dm - The `DMPLEX` object 9778 . output - If true, statistics will be displayed on `stdout` 9779 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9780 9781 Level: developer 9782 9783 Notes: 9784 This is mainly intended for debugging/testing purposes. 9785 9786 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9787 9788 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9789 @*/ 9790 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9791 { 9792 DM dmCoarse; 9793 cell_stats_t stats, globalStats; 9794 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9795 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9796 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9797 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9798 PetscMPIInt rank, size; 9799 9800 PetscFunctionBegin; 9801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9802 stats.min = PETSC_MAX_REAL; 9803 stats.max = PETSC_MIN_REAL; 9804 stats.sum = stats.squaresum = 0.; 9805 stats.count = 0; 9806 9807 PetscCallMPI(MPI_Comm_size(comm, &size)); 9808 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9809 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9810 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9811 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9812 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9813 for (c = cStart; c < cEnd; c++) { 9814 PetscInt i; 9815 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9816 9817 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9818 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9819 for (i = 0; i < PetscSqr(cdim); ++i) { 9820 frobJ += J[i] * J[i]; 9821 frobInvJ += invJ[i] * invJ[i]; 9822 } 9823 cond2 = frobJ * frobInvJ; 9824 cond = PetscSqrtReal(cond2); 9825 9826 stats.min = PetscMin(stats.min, cond); 9827 stats.max = PetscMax(stats.max, cond); 9828 stats.sum += cond; 9829 stats.squaresum += cond2; 9830 stats.count++; 9831 if (output && cond > limit) { 9832 PetscSection coordSection; 9833 Vec coordsLocal; 9834 PetscScalar *coords = NULL; 9835 PetscInt Nv, d, clSize, cl, *closure = NULL; 9836 9837 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9838 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9839 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9840 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9841 for (i = 0; i < Nv / cdim; ++i) { 9842 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9843 for (d = 0; d < cdim; ++d) { 9844 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9845 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9846 } 9847 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9848 } 9849 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9850 for (cl = 0; cl < clSize * 2; cl += 2) { 9851 const PetscInt edge = closure[cl]; 9852 9853 if ((edge >= eStart) && (edge < eEnd)) { 9854 PetscReal len; 9855 9856 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9857 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9858 } 9859 } 9860 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9861 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9862 } 9863 } 9864 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9865 9866 if (size > 1) { 9867 PetscMPIInt blockLengths[2] = {4, 1}; 9868 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9869 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9870 MPI_Op statReduce; 9871 9872 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9873 PetscCallMPI(MPI_Type_commit(&statType)); 9874 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9875 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9876 PetscCallMPI(MPI_Op_free(&statReduce)); 9877 PetscCallMPI(MPI_Type_free(&statType)); 9878 } else { 9879 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9880 } 9881 if (rank == 0) { 9882 count = globalStats.count; 9883 min = globalStats.min; 9884 max = globalStats.max; 9885 mean = globalStats.sum / globalStats.count; 9886 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9887 } 9888 9889 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)); 9890 PetscCall(PetscFree2(J, invJ)); 9891 9892 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9893 if (dmCoarse) { 9894 PetscBool isplex; 9895 9896 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9897 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9898 } 9899 PetscFunctionReturn(PETSC_SUCCESS); 9900 } 9901 9902 /*@ 9903 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9904 orthogonal quality below given tolerance. 9905 9906 Collective 9907 9908 Input Parameters: 9909 + dm - The `DMPLEX` object 9910 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9911 - atol - [0, 1] Absolute tolerance for tagging cells. 9912 9913 Output Parameters: 9914 + OrthQual - `Vec` containing orthogonal quality per cell 9915 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9916 9917 Options Database Keys: 9918 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9919 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9920 9921 Level: intermediate 9922 9923 Notes: 9924 Orthogonal quality is given by the following formula\: 9925 9926 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9927 9928 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 9929 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9930 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9931 calculating the cosine of the angle between these vectors. 9932 9933 Orthogonal quality ranges from 1 (best) to 0 (worst). 9934 9935 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9936 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9937 9938 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9939 9940 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9941 @*/ 9942 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9943 { 9944 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9945 PetscInt *idx; 9946 PetscScalar *oqVals; 9947 const PetscScalar *cellGeomArr, *faceGeomArr; 9948 PetscReal *ci, *fi, *Ai; 9949 MPI_Comm comm; 9950 Vec cellgeom, facegeom; 9951 DM dmFace, dmCell; 9952 IS glob; 9953 ISLocalToGlobalMapping ltog; 9954 PetscViewer vwr; 9955 9956 PetscFunctionBegin; 9957 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9958 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9959 PetscAssertPointer(OrthQual, 4); 9960 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9961 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9962 PetscCall(DMGetDimension(dm, &nc)); 9963 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9964 { 9965 DMPlexInterpolatedFlag interpFlag; 9966 9967 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9968 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9969 PetscMPIInt rank; 9970 9971 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9972 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9973 } 9974 } 9975 if (OrthQualLabel) { 9976 PetscAssertPointer(OrthQualLabel, 5); 9977 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9978 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9979 } else { 9980 *OrthQualLabel = NULL; 9981 } 9982 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9983 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9984 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9985 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9986 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9987 PetscCall(VecCreate(comm, OrthQual)); 9988 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9989 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9990 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9991 PetscCall(VecSetUp(*OrthQual)); 9992 PetscCall(ISDestroy(&glob)); 9993 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9994 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9995 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9996 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9997 PetscCall(VecGetDM(cellgeom, &dmCell)); 9998 PetscCall(VecGetDM(facegeom, &dmFace)); 9999 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 10000 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 10001 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 10002 PetscInt cellarr[2], *adj = NULL; 10003 PetscScalar *cArr, *fArr; 10004 PetscReal minvalc = 1.0, minvalf = 1.0; 10005 PetscFVCellGeom *cg; 10006 10007 idx[cellIter] = cell - cStart; 10008 cellarr[0] = cell; 10009 /* Make indexing into cellGeom easier */ 10010 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10011 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10012 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10013 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10014 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10015 PetscInt i; 10016 const PetscInt neigh = adj[cellneigh]; 10017 PetscReal normci = 0, normfi = 0, normai = 0; 10018 PetscFVCellGeom *cgneigh; 10019 PetscFVFaceGeom *fg; 10020 10021 /* Don't count ourselves in the neighbor list */ 10022 if (neigh == cell) continue; 10023 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10024 cellarr[1] = neigh; 10025 { 10026 PetscInt numcovpts; 10027 const PetscInt *covpts; 10028 10029 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10030 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10031 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10032 } 10033 10034 /* Compute c_i, f_i and their norms */ 10035 for (i = 0; i < nc; i++) { 10036 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10037 fi[i] = fg->centroid[i] - cg->centroid[i]; 10038 Ai[i] = fg->normal[i]; 10039 normci += PetscPowReal(ci[i], 2); 10040 normfi += PetscPowReal(fi[i], 2); 10041 normai += PetscPowReal(Ai[i], 2); 10042 } 10043 normci = PetscSqrtReal(normci); 10044 normfi = PetscSqrtReal(normfi); 10045 normai = PetscSqrtReal(normai); 10046 10047 /* Normalize and compute for each face-cell-normal pair */ 10048 for (i = 0; i < nc; i++) { 10049 ci[i] = ci[i] / normci; 10050 fi[i] = fi[i] / normfi; 10051 Ai[i] = Ai[i] / normai; 10052 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10053 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10054 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10055 } 10056 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10057 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10058 } 10059 PetscCall(PetscFree(adj)); 10060 PetscCall(PetscFree2(cArr, fArr)); 10061 /* Defer to cell if they're equal */ 10062 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10063 if (OrthQualLabel) { 10064 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10065 } 10066 } 10067 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10068 PetscCall(VecAssemblyBegin(*OrthQual)); 10069 PetscCall(VecAssemblyEnd(*OrthQual)); 10070 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10071 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10072 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10073 if (OrthQualLabel) { 10074 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10075 } 10076 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10077 PetscCall(PetscViewerDestroy(&vwr)); 10078 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10079 PetscFunctionReturn(PETSC_SUCCESS); 10080 } 10081 10082 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10083 * interpolator construction */ 10084 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10085 { 10086 PetscSection section, newSection, gsection; 10087 PetscSF sf; 10088 PetscBool hasConstraints, ghasConstraints; 10089 10090 PetscFunctionBegin; 10091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10092 PetscAssertPointer(odm, 2); 10093 PetscCall(DMGetLocalSection(dm, §ion)); 10094 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10095 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10096 if (!ghasConstraints) { 10097 PetscCall(PetscObjectReference((PetscObject)dm)); 10098 *odm = dm; 10099 PetscFunctionReturn(PETSC_SUCCESS); 10100 } 10101 PetscCall(DMClone(dm, odm)); 10102 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10103 PetscCall(DMGetLocalSection(*odm, &newSection)); 10104 PetscCall(DMGetPointSF(*odm, &sf)); 10105 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10106 PetscCall(DMSetGlobalSection(*odm, gsection)); 10107 PetscCall(PetscSectionDestroy(&gsection)); 10108 PetscFunctionReturn(PETSC_SUCCESS); 10109 } 10110 10111 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10112 { 10113 DM dmco, dmfo; 10114 Mat interpo; 10115 Vec rscale; 10116 Vec cglobalo, clocal; 10117 Vec fglobal, fglobalo, flocal; 10118 PetscBool regular; 10119 10120 PetscFunctionBegin; 10121 PetscCall(DMGetFullDM(dmc, &dmco)); 10122 PetscCall(DMGetFullDM(dmf, &dmfo)); 10123 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10124 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10125 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10126 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10127 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10128 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10129 PetscCall(VecSet(cglobalo, 0.)); 10130 PetscCall(VecSet(clocal, 0.)); 10131 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10132 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10133 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10134 PetscCall(VecSet(fglobal, 0.)); 10135 PetscCall(VecSet(fglobalo, 0.)); 10136 PetscCall(VecSet(flocal, 0.)); 10137 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10138 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10139 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10140 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10141 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10142 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10143 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10144 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10145 *shift = fglobal; 10146 PetscCall(VecDestroy(&flocal)); 10147 PetscCall(VecDestroy(&fglobalo)); 10148 PetscCall(VecDestroy(&clocal)); 10149 PetscCall(VecDestroy(&cglobalo)); 10150 PetscCall(VecDestroy(&rscale)); 10151 PetscCall(MatDestroy(&interpo)); 10152 PetscCall(DMDestroy(&dmfo)); 10153 PetscCall(DMDestroy(&dmco)); 10154 PetscFunctionReturn(PETSC_SUCCESS); 10155 } 10156 10157 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10158 { 10159 PetscObject shifto; 10160 Vec shift; 10161 10162 PetscFunctionBegin; 10163 if (!interp) { 10164 Vec rscale; 10165 10166 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10167 PetscCall(VecDestroy(&rscale)); 10168 } else { 10169 PetscCall(PetscObjectReference((PetscObject)interp)); 10170 } 10171 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10172 if (!shifto) { 10173 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10174 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10175 shifto = (PetscObject)shift; 10176 PetscCall(VecDestroy(&shift)); 10177 } 10178 shift = (Vec)shifto; 10179 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10180 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10181 PetscCall(MatDestroy(&interp)); 10182 PetscFunctionReturn(PETSC_SUCCESS); 10183 } 10184 10185 /* Pointwise interpolation 10186 Just code FEM for now 10187 u^f = I u^c 10188 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10189 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10190 I_{ij} = psi^f_i phi^c_j 10191 */ 10192 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10193 { 10194 PetscSection gsc, gsf; 10195 PetscInt m, n; 10196 void *ctx; 10197 DM cdm; 10198 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10199 10200 PetscFunctionBegin; 10201 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10202 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10203 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10204 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10205 10206 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10207 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10208 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10209 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10210 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10211 10212 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10213 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10214 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10215 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10216 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10217 if (scaling) { 10218 /* Use naive scaling */ 10219 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10220 } 10221 PetscFunctionReturn(PETSC_SUCCESS); 10222 } 10223 10224 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10225 { 10226 VecScatter ctx; 10227 10228 PetscFunctionBegin; 10229 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10230 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10231 PetscCall(VecScatterDestroy(&ctx)); 10232 PetscFunctionReturn(PETSC_SUCCESS); 10233 } 10234 10235 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[]) 10236 { 10237 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10238 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10239 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10240 } 10241 10242 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10243 { 10244 DM dmc; 10245 PetscDS ds; 10246 Vec ones, locmass; 10247 IS cellIS; 10248 PetscFormKey key; 10249 PetscInt depth; 10250 10251 PetscFunctionBegin; 10252 PetscCall(DMClone(dm, &dmc)); 10253 PetscCall(DMCopyDisc(dm, dmc)); 10254 PetscCall(DMGetDS(dmc, &ds)); 10255 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10256 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10257 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10258 else PetscCall(DMGetLocalVector(dm, &locmass)); 10259 PetscCall(DMGetLocalVector(dm, &ones)); 10260 PetscCall(DMPlexGetDepth(dm, &depth)); 10261 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10262 PetscCall(VecSet(locmass, 0.0)); 10263 PetscCall(VecSet(ones, 1.0)); 10264 key.label = NULL; 10265 key.value = 0; 10266 key.field = 0; 10267 key.part = 0; 10268 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10269 PetscCall(ISDestroy(&cellIS)); 10270 if (mass) { 10271 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10272 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10273 } 10274 PetscCall(DMRestoreLocalVector(dm, &ones)); 10275 if (lmass) *lmass = locmass; 10276 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10277 PetscCall(DMDestroy(&dmc)); 10278 PetscFunctionReturn(PETSC_SUCCESS); 10279 } 10280 10281 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10282 { 10283 PetscSection gsc, gsf; 10284 PetscInt m, n; 10285 void *ctx; 10286 DM cdm; 10287 PetscBool regular; 10288 10289 PetscFunctionBegin; 10290 if (dmFine == dmCoarse) { 10291 DM dmc; 10292 PetscDS ds; 10293 PetscWeakForm wf; 10294 Vec u; 10295 IS cellIS; 10296 PetscFormKey key; 10297 PetscInt depth; 10298 10299 PetscCall(DMClone(dmFine, &dmc)); 10300 PetscCall(DMCopyDisc(dmFine, dmc)); 10301 PetscCall(DMGetDS(dmc, &ds)); 10302 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10303 PetscCall(PetscWeakFormClear(wf)); 10304 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10305 PetscCall(DMCreateMatrix(dmc, mass)); 10306 PetscCall(DMGetLocalVector(dmc, &u)); 10307 PetscCall(DMPlexGetDepth(dmc, &depth)); 10308 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10309 PetscCall(MatZeroEntries(*mass)); 10310 key.label = NULL; 10311 key.value = 0; 10312 key.field = 0; 10313 key.part = 0; 10314 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10315 PetscCall(ISDestroy(&cellIS)); 10316 PetscCall(DMRestoreLocalVector(dmc, &u)); 10317 PetscCall(DMDestroy(&dmc)); 10318 } else { 10319 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10320 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10321 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10322 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10323 10324 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10325 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10326 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10327 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10328 10329 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10330 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10331 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10332 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10333 } 10334 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10335 PetscFunctionReturn(PETSC_SUCCESS); 10336 } 10337 10338 /*@ 10339 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10340 10341 Input Parameter: 10342 . dm - The `DMPLEX` object 10343 10344 Output Parameter: 10345 . regular - The flag 10346 10347 Level: intermediate 10348 10349 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10350 @*/ 10351 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10352 { 10353 PetscFunctionBegin; 10354 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10355 PetscAssertPointer(regular, 2); 10356 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10357 PetscFunctionReturn(PETSC_SUCCESS); 10358 } 10359 10360 /*@ 10361 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10362 10363 Input Parameters: 10364 + dm - The `DMPLEX` object 10365 - regular - The flag 10366 10367 Level: intermediate 10368 10369 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10370 @*/ 10371 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10372 { 10373 PetscFunctionBegin; 10374 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10375 ((DM_Plex *)dm->data)->regularRefinement = regular; 10376 PetscFunctionReturn(PETSC_SUCCESS); 10377 } 10378 10379 /*@ 10380 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10381 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10382 10383 Not Collective 10384 10385 Input Parameter: 10386 . dm - The `DMPLEX` object 10387 10388 Output Parameters: 10389 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10390 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10391 10392 Level: intermediate 10393 10394 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10395 @*/ 10396 PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS) 10397 { 10398 DM_Plex *plex = (DM_Plex *)dm->data; 10399 10400 PetscFunctionBegin; 10401 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10402 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10403 if (anchorSection) *anchorSection = plex->anchorSection; 10404 if (anchorIS) *anchorIS = plex->anchorIS; 10405 PetscFunctionReturn(PETSC_SUCCESS); 10406 } 10407 10408 /*@ 10409 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10410 10411 Collective 10412 10413 Input Parameters: 10414 + dm - The `DMPLEX` object 10415 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10416 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10417 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10418 10419 Level: intermediate 10420 10421 Notes: 10422 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10423 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10424 combination of other points' degrees of freedom. 10425 10426 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10427 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10428 10429 The reference counts of `anchorSection` and `anchorIS` are incremented. 10430 10431 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10432 @*/ 10433 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10434 { 10435 DM_Plex *plex = (DM_Plex *)dm->data; 10436 PetscMPIInt result; 10437 10438 PetscFunctionBegin; 10439 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10440 if (anchorSection) { 10441 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10442 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10443 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10444 } 10445 if (anchorIS) { 10446 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10447 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10448 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10449 } 10450 10451 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10452 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10453 plex->anchorSection = anchorSection; 10454 10455 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10456 PetscCall(ISDestroy(&plex->anchorIS)); 10457 plex->anchorIS = anchorIS; 10458 10459 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10460 PetscInt size, a, pStart, pEnd; 10461 const PetscInt *anchors; 10462 10463 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10464 PetscCall(ISGetLocalSize(anchorIS, &size)); 10465 PetscCall(ISGetIndices(anchorIS, &anchors)); 10466 for (a = 0; a < size; a++) { 10467 PetscInt p; 10468 10469 p = anchors[a]; 10470 if (p >= pStart && p < pEnd) { 10471 PetscInt dof; 10472 10473 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10474 if (dof) { 10475 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10476 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10477 } 10478 } 10479 } 10480 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10481 } 10482 /* reset the generic constraints */ 10483 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10484 PetscFunctionReturn(PETSC_SUCCESS); 10485 } 10486 10487 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10488 { 10489 PetscSection anchorSection; 10490 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10491 10492 PetscFunctionBegin; 10493 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10494 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10495 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10496 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10497 if (numFields) { 10498 PetscInt f; 10499 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10500 10501 for (f = 0; f < numFields; f++) { 10502 PetscInt numComp; 10503 10504 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10505 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10506 } 10507 } 10508 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10509 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10510 pStart = PetscMax(pStart, sStart); 10511 pEnd = PetscMin(pEnd, sEnd); 10512 pEnd = PetscMax(pStart, pEnd); 10513 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10514 for (p = pStart; p < pEnd; p++) { 10515 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10516 if (dof) { 10517 PetscCall(PetscSectionGetDof(section, p, &dof)); 10518 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10519 for (f = 0; f < numFields; f++) { 10520 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10521 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10522 } 10523 } 10524 } 10525 PetscCall(PetscSectionSetUp(*cSec)); 10526 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10527 PetscFunctionReturn(PETSC_SUCCESS); 10528 } 10529 10530 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10531 { 10532 PetscSection aSec; 10533 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10534 const PetscInt *anchors; 10535 PetscInt numFields, f; 10536 IS aIS; 10537 MatType mtype; 10538 PetscBool iscuda, iskokkos; 10539 10540 PetscFunctionBegin; 10541 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10542 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10543 PetscCall(PetscSectionGetStorageSize(section, &n)); 10544 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10545 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10546 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10547 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10548 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10549 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10550 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10551 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10552 else mtype = MATSEQAIJ; 10553 PetscCall(MatSetType(*cMat, mtype)); 10554 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10555 PetscCall(ISGetIndices(aIS, &anchors)); 10556 /* cSec will be a subset of aSec and section */ 10557 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10558 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10559 PetscCall(PetscMalloc1(m + 1, &i)); 10560 i[0] = 0; 10561 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10562 for (p = pStart; p < pEnd; p++) { 10563 PetscInt rDof, rOff, r; 10564 10565 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10566 if (!rDof) continue; 10567 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10568 if (numFields) { 10569 for (f = 0; f < numFields; f++) { 10570 annz = 0; 10571 for (r = 0; r < rDof; r++) { 10572 a = anchors[rOff + r]; 10573 if (a < sStart || a >= sEnd) continue; 10574 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10575 annz += aDof; 10576 } 10577 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10578 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10579 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10580 } 10581 } else { 10582 annz = 0; 10583 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10584 for (q = 0; q < dof; q++) { 10585 a = anchors[rOff + q]; 10586 if (a < sStart || a >= sEnd) continue; 10587 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10588 annz += aDof; 10589 } 10590 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10591 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10592 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10593 } 10594 } 10595 nnz = i[m]; 10596 PetscCall(PetscMalloc1(nnz, &j)); 10597 offset = 0; 10598 for (p = pStart; p < pEnd; p++) { 10599 if (numFields) { 10600 for (f = 0; f < numFields; f++) { 10601 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10602 for (q = 0; q < dof; q++) { 10603 PetscInt rDof, rOff, r; 10604 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10605 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10606 for (r = 0; r < rDof; r++) { 10607 PetscInt s; 10608 10609 a = anchors[rOff + r]; 10610 if (a < sStart || a >= sEnd) continue; 10611 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10612 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10613 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10614 } 10615 } 10616 } 10617 } else { 10618 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10619 for (q = 0; q < dof; q++) { 10620 PetscInt rDof, rOff, r; 10621 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10622 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10623 for (r = 0; r < rDof; r++) { 10624 PetscInt s; 10625 10626 a = anchors[rOff + r]; 10627 if (a < sStart || a >= sEnd) continue; 10628 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10629 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10630 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10631 } 10632 } 10633 } 10634 } 10635 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10636 PetscCall(PetscFree(i)); 10637 PetscCall(PetscFree(j)); 10638 PetscCall(ISRestoreIndices(aIS, &anchors)); 10639 PetscFunctionReturn(PETSC_SUCCESS); 10640 } 10641 10642 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10643 { 10644 DM_Plex *plex = (DM_Plex *)dm->data; 10645 PetscSection anchorSection, section, cSec; 10646 Mat cMat; 10647 10648 PetscFunctionBegin; 10649 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10650 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10651 if (anchorSection) { 10652 PetscInt Nf; 10653 10654 PetscCall(DMGetLocalSection(dm, §ion)); 10655 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10656 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10657 PetscCall(DMGetNumFields(dm, &Nf)); 10658 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10659 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10660 PetscCall(PetscSectionDestroy(&cSec)); 10661 PetscCall(MatDestroy(&cMat)); 10662 } 10663 PetscFunctionReturn(PETSC_SUCCESS); 10664 } 10665 10666 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10667 { 10668 IS subis; 10669 PetscSection section, subsection; 10670 10671 PetscFunctionBegin; 10672 PetscCall(DMGetLocalSection(dm, §ion)); 10673 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10674 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10675 /* Create subdomain */ 10676 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10677 /* Create submodel */ 10678 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10679 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10680 PetscCall(DMSetLocalSection(*subdm, subsection)); 10681 PetscCall(PetscSectionDestroy(&subsection)); 10682 PetscCall(DMCopyDisc(dm, *subdm)); 10683 /* Create map from submodel to global model */ 10684 if (is) { 10685 PetscSection sectionGlobal, subsectionGlobal; 10686 IS spIS; 10687 const PetscInt *spmap; 10688 PetscInt *subIndices; 10689 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10690 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10691 10692 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10693 PetscCall(ISGetIndices(spIS, &spmap)); 10694 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10695 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10696 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10697 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10698 for (p = pStart; p < pEnd; ++p) { 10699 PetscInt gdof, pSubSize = 0; 10700 10701 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10702 if (gdof > 0) { 10703 for (f = 0; f < Nf; ++f) { 10704 PetscInt fdof, fcdof; 10705 10706 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10707 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10708 pSubSize += fdof - fcdof; 10709 } 10710 subSize += pSubSize; 10711 if (pSubSize) { 10712 if (bs < 0) { 10713 bs = pSubSize; 10714 } else if (bs != pSubSize) { 10715 /* Layout does not admit a pointwise block size */ 10716 bs = 1; 10717 } 10718 } 10719 } 10720 } 10721 /* Must have same blocksize on all procs (some might have no points) */ 10722 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10723 bsLocal[1] = bs; 10724 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10725 if (bsMinMax[0] != bsMinMax[1]) { 10726 bs = 1; 10727 } else { 10728 bs = bsMinMax[0]; 10729 } 10730 PetscCall(PetscMalloc1(subSize, &subIndices)); 10731 for (p = pStart; p < pEnd; ++p) { 10732 PetscInt gdof, goff; 10733 10734 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10735 if (gdof > 0) { 10736 const PetscInt point = spmap[p]; 10737 10738 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10739 for (f = 0; f < Nf; ++f) { 10740 PetscInt fdof, fcdof, fc, f2, poff = 0; 10741 10742 /* Can get rid of this loop by storing field information in the global section */ 10743 for (f2 = 0; f2 < f; ++f2) { 10744 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10745 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10746 poff += fdof - fcdof; 10747 } 10748 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10749 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10750 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10751 } 10752 } 10753 } 10754 PetscCall(ISRestoreIndices(spIS, &spmap)); 10755 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10756 if (bs > 1) { 10757 /* We need to check that the block size does not come from non-contiguous fields */ 10758 PetscInt i, j, set = 1; 10759 for (i = 0; i < subSize; i += bs) { 10760 for (j = 0; j < bs; ++j) { 10761 if (subIndices[i + j] != subIndices[i] + j) { 10762 set = 0; 10763 break; 10764 } 10765 } 10766 } 10767 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10768 } 10769 /* Attach nullspace */ 10770 for (f = 0; f < Nf; ++f) { 10771 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10772 if ((*subdm)->nullspaceConstructors[f]) break; 10773 } 10774 if (f < Nf) { 10775 MatNullSpace nullSpace; 10776 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10777 10778 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10779 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10780 } 10781 } 10782 PetscFunctionReturn(PETSC_SUCCESS); 10783 } 10784 10785 /*@ 10786 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10787 10788 Input Parameters: 10789 + dm - The `DM` 10790 - dummy - unused argument 10791 10792 Options Database Key: 10793 . -dm_plex_monitor_throughput - Activate the monitor 10794 10795 Level: developer 10796 10797 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10798 @*/ 10799 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10800 { 10801 PetscLogHandler default_handler; 10802 10803 PetscFunctionBegin; 10804 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10805 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10806 if (default_handler) { 10807 PetscLogEvent event; 10808 PetscEventPerfInfo eventInfo; 10809 PetscLogDouble cellRate, flopRate; 10810 PetscInt cStart, cEnd, Nf, N; 10811 const char *name; 10812 10813 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10814 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10815 PetscCall(DMGetNumFields(dm, &Nf)); 10816 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10817 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10818 N = (cEnd - cStart) * Nf * eventInfo.count; 10819 flopRate = eventInfo.flops / eventInfo.time; 10820 cellRate = N / eventInfo.time; 10821 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)); 10822 } else { 10823 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."); 10824 } 10825 PetscFunctionReturn(PETSC_SUCCESS); 10826 } 10827