1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_CreateBoxSFC, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 /* Logging support */ 18 PetscLogEvent DMPLEX_DistributionView, DMPLEX_DistributionLoad; 19 20 PetscBool Plexcite = PETSC_FALSE; 21 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 22 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 23 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 24 "journal = {SIAM Journal on Scientific Computing},\n" 25 "volume = {38},\n" 26 "number = {5},\n" 27 "pages = {S143--S155},\n" 28 "eprint = {http://arxiv.org/abs/1506.07749},\n" 29 "doi = {10.1137/15M1026092},\n" 30 "year = {2016},\n" 31 "petsc_uses={DMPlex},\n}\n"; 32 33 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 34 35 /*@ 36 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 37 38 Input Parameter: 39 . dm - The `DMPLEX` object 40 41 Output Parameter: 42 . simplex - Flag checking for a simplex 43 44 Level: intermediate 45 46 Note: 47 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 48 If the mesh has no cells, this returns `PETSC_FALSE`. 49 50 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 51 @*/ 52 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 53 { 54 DMPolytopeType ct; 55 PetscInt cStart, cEnd; 56 57 PetscFunctionBegin; 58 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 59 if (cEnd <= cStart) { 60 *simplex = PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 64 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 65 PetscFunctionReturn(PETSC_SUCCESS); 66 } 67 68 /*@ 69 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 70 71 Input Parameters: 72 + dm - The `DMPLEX` object 73 - height - The cell height in the Plex, 0 is the default 74 75 Output Parameters: 76 + cStart - The first "normal" cell, pass `NULL` if not needed 77 - cEnd - The upper bound on "normal" cells, pass `NULL` if not needed 78 79 Level: developer 80 81 Note: 82 This function requires that tensor cells are ordered last. 83 84 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 85 @*/ 86 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PeOp PetscInt *cStart, PeOp PetscInt *cEnd) 87 { 88 DMLabel ctLabel; 89 IS valueIS; 90 const PetscInt *ctypes; 91 PetscBool found = PETSC_FALSE; 92 PetscInt Nct, cS = PETSC_INT_MAX, cE = 0; 93 94 PetscFunctionBegin; 95 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 96 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 97 PetscCall(ISGetLocalSize(valueIS, &Nct)); 98 PetscCall(ISGetIndices(valueIS, &ctypes)); 99 for (PetscInt t = 0; t < Nct; ++t) { 100 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 101 PetscInt ctS, ctE, ht; 102 103 if (ct == DM_POLYTOPE_UNKNOWN) { 104 // If any cells are not typed, just use all cells 105 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 106 break; 107 } 108 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 109 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 110 if (ctS >= ctE) continue; 111 // Check that a point has the right height 112 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 113 if (ht != height) continue; 114 cS = PetscMin(cS, ctS); 115 cE = PetscMax(cE, ctE); 116 found = PETSC_TRUE; 117 } 118 if (!Nct || !found) cS = cE = 0; 119 PetscCall(ISDestroy(&valueIS)); 120 // Reset label for fast lookup 121 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 122 if (cStart) *cStart = cS; 123 if (cEnd) *cEnd = cE; 124 PetscFunctionReturn(PETSC_SUCCESS); 125 } 126 127 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 128 { 129 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 130 PetscInt *sStart, *sEnd; 131 PetscViewerVTKFieldType *ft; 132 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 133 DMLabel depthLabel, ctLabel; 134 135 PetscFunctionBegin; 136 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 137 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 138 PetscCall(DMGetCoordinateDim(dm, &cdim)); 139 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 140 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 141 if (field >= 0) { 142 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 143 } else { 144 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 145 } 146 147 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 148 PetscCall(DMPlexGetDepth(dm, &depth)); 149 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 150 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 151 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 152 const DMPolytopeType ict = (DMPolytopeType)c; 153 PetscInt dep; 154 155 if (ict == DM_POLYTOPE_FV_GHOST) continue; 156 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 157 if (pStart >= 0) { 158 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 159 if (dep != depth - cellHeight) continue; 160 } 161 if (field >= 0) { 162 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 163 } else { 164 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 165 } 166 } 167 168 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 169 *types = 0; 170 171 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 172 if (globalvcdof[c]) ++(*types); 173 } 174 175 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 176 t = 0; 177 if (globalvcdof[DM_NUM_POLYTOPES]) { 178 sStart[t] = vStart; 179 sEnd[t] = vEnd; 180 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 181 ++t; 182 } 183 184 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 185 if (globalvcdof[c]) { 186 const DMPolytopeType ict = (DMPolytopeType)c; 187 188 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 189 sStart[t] = cStart; 190 sEnd[t] = cEnd; 191 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 192 ++t; 193 } 194 } 195 196 if (!*types) { 197 if (field >= 0) { 198 const char *fieldname; 199 200 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 201 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 202 } else { 203 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 204 } 205 } 206 207 *ssStart = sStart; 208 *ssEnd = sEnd; 209 *sft = ft; 210 PetscFunctionReturn(PETSC_SUCCESS); 211 } 212 213 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 214 { 215 PetscFunctionBegin; 216 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 217 PetscFunctionReturn(PETSC_SUCCESS); 218 } 219 220 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 221 { 222 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 223 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 224 225 PetscFunctionBegin; 226 *ft = PETSC_VTK_INVALID; 227 PetscCall(DMGetCoordinateDim(dm, &cdim)); 228 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 229 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 230 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 231 if (field >= 0) { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 234 } else { 235 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 236 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 237 } 238 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 239 if (globalvcdof[0]) { 240 *sStart = vStart; 241 *sEnd = vEnd; 242 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 243 else *ft = PETSC_VTK_POINT_FIELD; 244 } else if (globalvcdof[1]) { 245 *sStart = cStart; 246 *sEnd = cEnd; 247 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 248 else *ft = PETSC_VTK_CELL_FIELD; 249 } else { 250 if (field >= 0) { 251 const char *fieldname; 252 253 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 254 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 255 } else { 256 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n")); 257 } 258 } 259 PetscFunctionReturn(PETSC_SUCCESS); 260 } 261 262 /*@ 263 DMPlexVecView1D - Plot many 1D solutions on the same line graph 264 265 Collective 266 267 Input Parameters: 268 + dm - The `DMPLEX` object 269 . n - The number of vectors 270 . u - The array of local vectors 271 - viewer - The `PetscViewer` 272 273 Level: advanced 274 275 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 276 @*/ 277 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 278 { 279 DM cdm; 280 PetscDS ds; 281 PetscDraw draw = NULL; 282 PetscDrawLG lg; 283 Vec coordinates; 284 const PetscScalar *coords, **sol; 285 PetscReal *vals; 286 PetscInt *Nc; 287 PetscInt Nf, Nl, vStart, vEnd, eStart, eEnd; 288 char **names; 289 290 PetscFunctionBegin; 291 PetscCall(DMGetCoordinateDM(dm, &cdm)); 292 PetscCall(DMGetDS(dm, &ds)); 293 PetscCall(PetscDSGetNumFields(ds, &Nf)); 294 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 295 PetscCall(PetscDSGetComponents(ds, &Nc)); 296 297 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 298 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 299 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 300 301 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 302 for (PetscInt i = 0, l = 0; i < n; ++i) { 303 const char *vname; 304 305 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 306 for (PetscInt f = 0; f < Nf; ++f) { 307 PetscObject disc; 308 const char *fname; 309 char tmpname[PETSC_MAX_PATH_LEN]; 310 311 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 312 /* TODO Create names for components */ 313 for (PetscInt c = 0; c < Nc[f]; ++c, ++l) { 314 PetscCall(PetscObjectGetName(disc, &fname)); 315 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 316 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 317 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 318 PetscCall(PetscStrallocpy(tmpname, &names[l])); 319 } 320 } 321 } 322 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 323 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 324 PetscCall(VecGetArrayRead(coordinates, &coords)); 325 for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 326 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 327 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 328 PetscSection s; 329 PetscInt cdof, vdof; 330 331 PetscCall(DMGetLocalSection(dm, &s)); 332 PetscCall(PetscSectionGetDof(s, eStart, &cdof)); 333 PetscCall(PetscSectionGetDof(s, vStart, &vdof)); 334 if (cdof) { 335 if (vdof) { 336 // P_2 337 PetscInt vFirst = -1; 338 339 for (PetscInt e = eStart; e < eEnd; ++e) { 340 PetscScalar *xa, *xb, *svals; 341 const PetscInt *cone; 342 343 PetscCall(DMPlexGetCone(dm, e, &cone)); 344 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 345 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 346 if (e == eStart) vFirst = cone[0]; 347 for (PetscInt i = 0; i < n; ++i) { 348 PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals)); 349 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 350 } 351 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals)); 352 if (e == eEnd - 1 && cone[1] != vFirst) { 353 for (PetscInt i = 0; i < n; ++i) { 354 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 355 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 356 } 357 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 358 for (PetscInt i = 0; i < n; ++i) { 359 PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals)); 360 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 361 } 362 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals)); 363 } 364 } 365 } else { 366 // P_0 367 for (PetscInt e = eStart; e < eEnd; ++e) { 368 PetscScalar *xa, *xb, *svals; 369 const PetscInt *cone; 370 371 PetscCall(DMPlexGetCone(dm, e, &cone)); 372 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 373 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 374 for (PetscInt i = 0; i < n; ++i) { 375 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 376 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 377 } 378 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 379 } 380 } 381 } else if (vdof) { 382 // P_1 383 for (PetscInt v = vStart; v < vEnd; ++v) { 384 PetscScalar *x, *svals; 385 386 PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x)); 387 for (PetscInt i = 0; i < n; ++i) { 388 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 389 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 390 } 391 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 392 } 393 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Discretization not supported"); 394 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 395 for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 396 for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 397 PetscCall(PetscFree3(sol, names, vals)); 398 399 PetscCall(PetscDrawLGDraw(lg)); 400 PetscCall(PetscDrawLGDestroy(&lg)); 401 PetscFunctionReturn(PETSC_SUCCESS); 402 } 403 404 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 405 { 406 DM dm; 407 408 PetscFunctionBegin; 409 PetscCall(VecGetDM(u, &dm)); 410 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 411 PetscFunctionReturn(PETSC_SUCCESS); 412 } 413 414 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 415 { 416 DM dm; 417 PetscSection s; 418 PetscDraw draw, popup; 419 DM cdm; 420 PetscSection coordSection; 421 Vec coordinates; 422 const PetscScalar *array; 423 PetscReal lbound[3], ubound[3]; 424 PetscReal vbound[2], time; 425 PetscBool flg; 426 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 427 const char *name; 428 char title[PETSC_MAX_PATH_LEN]; 429 430 PetscFunctionBegin; 431 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 432 PetscCall(VecGetDM(v, &dm)); 433 PetscCall(DMGetCoordinateDim(dm, &dim)); 434 PetscCall(DMGetLocalSection(dm, &s)); 435 PetscCall(PetscSectionGetNumFields(s, &Nf)); 436 PetscCall(DMGetCoarsenLevel(dm, &level)); 437 PetscCall(DMGetCoordinateDM(dm, &cdm)); 438 PetscCall(DMGetLocalSection(cdm, &coordSection)); 439 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 440 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 441 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 442 443 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 444 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 445 446 PetscCall(VecGetLocalSize(coordinates, &N)); 447 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 448 PetscCall(PetscDrawClear(draw)); 449 450 /* Could implement something like DMDASelectFields() */ 451 for (f = 0; f < Nf; ++f) { 452 DM fdm = dm; 453 Vec fv = v; 454 IS fis; 455 char prefix[PETSC_MAX_PATH_LEN]; 456 const char *fname; 457 458 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 459 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 460 461 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 462 else prefix[0] = '\0'; 463 if (Nf > 1) { 464 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 465 PetscCall(VecGetSubVector(v, fis, &fv)); 466 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 467 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 468 } 469 for (comp = 0; comp < Nc; ++comp, ++w) { 470 PetscInt nmax = 2; 471 472 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 473 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 474 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 475 PetscCall(PetscDrawSetTitle(draw, title)); 476 477 /* TODO Get max and min only for this component */ 478 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 479 if (!flg) { 480 PetscCall(VecMin(fv, NULL, &vbound[0])); 481 PetscCall(VecMax(fv, NULL, &vbound[1])); 482 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 483 } 484 485 PetscCall(PetscDrawGetPopup(draw, &popup)); 486 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 487 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 488 PetscCall(VecGetArrayRead(fv, &array)); 489 for (c = cStart; c < cEnd; ++c) { 490 DMPolytopeType ct; 491 PetscScalar *coords = NULL, *a = NULL; 492 const PetscScalar *coords_arr; 493 PetscBool isDG; 494 PetscInt numCoords; 495 int color[4] = {-1, -1, -1, -1}; 496 497 PetscCall(DMPlexGetCellType(dm, c, &ct)); 498 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 499 if (a) { 500 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 501 color[1] = color[2] = color[3] = color[0]; 502 } else { 503 PetscScalar *vals = NULL; 504 PetscInt numVals, va; 505 506 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 507 if (!numVals) { 508 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 509 continue; 510 } 511 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 512 switch (numVals / Nc) { 513 case 1: /* P1 Clamped Segment Prism */ 514 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 515 PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]); 516 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 517 break; 518 case 3: /* P1 Triangle */ 519 case 4: /* P1 Quadrangle */ 520 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 521 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 522 break; 523 case 6: /* P2 Triangle */ 524 case 8: /* P2 Quadrangle */ 525 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 526 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 527 break; 528 default: 529 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 530 } 531 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 532 } 533 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 534 switch (numCoords) { 535 case 6: 536 case 12: /* Localized triangle */ 537 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 538 break; 539 case 8: 540 case 16: /* Localized quadrilateral */ 541 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 542 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 543 } else { 544 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 545 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 546 } 547 break; 548 default: 549 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 550 } 551 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 552 } 553 PetscCall(VecRestoreArrayRead(fv, &array)); 554 PetscCall(PetscDrawFlush(draw)); 555 PetscCall(PetscDrawPause(draw)); 556 PetscCall(PetscDrawSave(draw)); 557 } 558 if (Nf > 1) { 559 PetscCall(VecRestoreSubVector(v, fis, &fv)); 560 PetscCall(ISDestroy(&fis)); 561 PetscCall(DMDestroy(&fdm)); 562 } 563 } 564 PetscFunctionReturn(PETSC_SUCCESS); 565 } 566 567 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 568 { 569 DM dm; 570 PetscDraw draw; 571 PetscInt dim; 572 PetscBool isnull; 573 574 PetscFunctionBegin; 575 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 576 PetscCall(PetscDrawIsNull(draw, &isnull)); 577 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 578 579 PetscCall(VecGetDM(v, &dm)); 580 PetscCall(DMGetCoordinateDim(dm, &dim)); 581 switch (dim) { 582 case 1: 583 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 584 break; 585 case 2: 586 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 587 break; 588 default: 589 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 590 } 591 PetscFunctionReturn(PETSC_SUCCESS); 592 } 593 594 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 595 { 596 DM dm; 597 Vec locv; 598 const char *name; 599 PetscSection section; 600 PetscInt pStart, pEnd; 601 PetscInt numFields; 602 PetscViewerVTKFieldType ft; 603 604 PetscFunctionBegin; 605 PetscCall(VecGetDM(v, &dm)); 606 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 607 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 608 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 609 PetscCall(VecCopy(v, locv)); 610 PetscCall(DMGetLocalSection(dm, §ion)); 611 PetscCall(PetscSectionGetNumFields(section, &numFields)); 612 if (!numFields) { 613 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 614 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 615 } else { 616 PetscInt f; 617 618 for (f = 0; f < numFields; f++) { 619 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 620 if (ft == PETSC_VTK_INVALID) continue; 621 PetscCall(PetscObjectReference((PetscObject)locv)); 622 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 623 } 624 PetscCall(VecDestroy(&locv)); 625 } 626 PetscFunctionReturn(PETSC_SUCCESS); 627 } 628 629 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 630 { 631 DM dm; 632 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython; 633 634 PetscFunctionBegin; 635 PetscCall(VecGetDM(v, &dm)); 636 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 640 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 641 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 642 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 643 if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) { 644 PetscInt i, numFields; 645 PetscObject fe; 646 PetscBool fem = PETSC_FALSE; 647 Vec locv = v; 648 const char *name; 649 PetscInt step; 650 PetscReal time; 651 652 PetscCall(DMGetNumFields(dm, &numFields)); 653 for (i = 0; i < numFields; i++) { 654 PetscCall(DMGetField(dm, i, NULL, &fe)); 655 if (fe->classid == PETSCFE_CLASSID) { 656 fem = PETSC_TRUE; 657 break; 658 } 659 } 660 if (fem) { 661 PetscObject isZero; 662 663 PetscCall(DMGetLocalVector(dm, &locv)); 664 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 665 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 666 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 667 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 668 PetscCall(VecCopy(v, locv)); 669 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 670 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 671 } 672 if (isvtk) { 673 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 674 } else if (ishdf5) { 675 #if defined(PETSC_HAVE_HDF5) 676 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 677 #else 678 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 679 #endif 680 } else if (isdraw) { 681 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 682 } else if (ispython) { 683 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv)); 684 } else if (isglvis) { 685 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 686 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 687 PetscCall(VecView_GLVis(locv, viewer)); 688 } else if (iscgns) { 689 #if defined(PETSC_HAVE_CGNS) 690 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 691 #else 692 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 693 #endif 694 } 695 if (fem) { 696 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 697 PetscCall(DMRestoreLocalVector(dm, &locv)); 698 } 699 } else { 700 PetscBool isseq; 701 702 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 703 if (isseq) PetscCall(VecView_Seq(v, viewer)); 704 else PetscCall(VecView_MPI(v, viewer)); 705 } 706 PetscFunctionReturn(PETSC_SUCCESS); 707 } 708 709 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 710 { 711 DM dm; 712 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython; 713 714 PetscFunctionBegin; 715 PetscCall(VecGetDM(v, &dm)); 716 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 721 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 722 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 723 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 724 if (isvtk || isdraw || isglvis || iscgns || ispython) { 725 Vec locv; 726 PetscObject isZero; 727 const char *name; 728 729 PetscCall(DMGetLocalVector(dm, &locv)); 730 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 731 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 732 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 733 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 734 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 735 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 736 PetscCall(VecView_Plex_Local(locv, viewer)); 737 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 738 PetscCall(DMRestoreLocalVector(dm, &locv)); 739 } else if (ishdf5) { 740 #if defined(PETSC_HAVE_HDF5) 741 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 742 #else 743 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 744 #endif 745 } else if (isexodusii) { 746 #if defined(PETSC_HAVE_EXODUSII) 747 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 748 #else 749 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 750 #endif 751 } else { 752 PetscBool isseq; 753 754 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 755 if (isseq) PetscCall(VecView_Seq(v, viewer)); 756 else PetscCall(VecView_MPI(v, viewer)); 757 } 758 PetscFunctionReturn(PETSC_SUCCESS); 759 } 760 761 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 762 { 763 DM dm; 764 MPI_Comm comm; 765 PetscViewerFormat format; 766 Vec v; 767 PetscBool isvtk, ishdf5; 768 769 PetscFunctionBegin; 770 PetscCall(VecGetDM(originalv, &dm)); 771 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 772 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 773 PetscCall(PetscViewerGetFormat(viewer, &format)); 774 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 775 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 776 if (format == PETSC_VIEWER_NATIVE) { 777 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 778 /* this need a better fix */ 779 if (dm->useNatural) { 780 if (dm->sfNatural) { 781 const char *vecname; 782 PetscInt n, nroots; 783 784 PetscCall(VecGetLocalSize(originalv, &n)); 785 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 786 if (n == nroots) { 787 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 788 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 789 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 790 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 791 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 792 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 793 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 794 } else v = originalv; 795 } else v = originalv; 796 797 if (ishdf5) { 798 #if defined(PETSC_HAVE_HDF5) 799 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 800 #else 801 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 802 #endif 803 } else if (isvtk) { 804 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 805 } else { 806 PetscBool isseq; 807 808 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 809 if (isseq) PetscCall(VecView_Seq(v, viewer)); 810 else PetscCall(VecView_MPI(v, viewer)); 811 } 812 if (v != originalv) PetscCall(VecDestroy(&v)); 813 PetscFunctionReturn(PETSC_SUCCESS); 814 } 815 816 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 817 { 818 DM dm; 819 PetscBool ishdf5; 820 821 PetscFunctionBegin; 822 PetscCall(VecGetDM(v, &dm)); 823 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 824 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 825 if (ishdf5) { 826 DM dmBC; 827 Vec gv; 828 const char *name; 829 830 PetscCall(DMGetOutputDM(dm, &dmBC)); 831 PetscCall(DMGetGlobalVector(dmBC, &gv)); 832 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 833 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 834 PetscCall(VecLoad_Default(gv, viewer)); 835 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 836 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 837 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 838 } else PetscCall(VecLoad_Default(v, viewer)); 839 PetscFunctionReturn(PETSC_SUCCESS); 840 } 841 842 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 843 { 844 DM dm; 845 PetscBool ishdf5, isexodusii, iscgns; 846 847 PetscFunctionBegin; 848 PetscCall(VecGetDM(v, &dm)); 849 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 850 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 851 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 852 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 853 if (ishdf5) { 854 #if defined(PETSC_HAVE_HDF5) 855 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 856 #else 857 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 858 #endif 859 } else if (isexodusii) { 860 #if defined(PETSC_HAVE_EXODUSII) 861 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 862 #else 863 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 864 #endif 865 } else if (iscgns) { 866 #if defined(PETSC_HAVE_CGNS) 867 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 868 #else 869 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 870 #endif 871 } else PetscCall(VecLoad_Default(v, viewer)); 872 PetscFunctionReturn(PETSC_SUCCESS); 873 } 874 875 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 876 { 877 DM dm; 878 PetscViewerFormat format; 879 PetscBool ishdf5; 880 881 PetscFunctionBegin; 882 PetscCall(VecGetDM(originalv, &dm)); 883 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 884 PetscCall(PetscViewerGetFormat(viewer, &format)); 885 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 886 if (format == PETSC_VIEWER_NATIVE) { 887 if (dm->useNatural) { 888 if (dm->sfNatural) { 889 if (ishdf5) { 890 #if defined(PETSC_HAVE_HDF5) 891 Vec v; 892 const char *vecname; 893 894 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 895 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 896 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 897 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 898 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 899 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 900 PetscCall(VecDestroy(&v)); 901 #else 902 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 903 #endif 904 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 905 } 906 } else PetscCall(VecLoad_Default(originalv, viewer)); 907 } 908 PetscFunctionReturn(PETSC_SUCCESS); 909 } 910 911 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 912 { 913 PetscSection coordSection; 914 Vec coordinates; 915 DMLabel depthLabel, celltypeLabel; 916 const char *name[4]; 917 const PetscScalar *a; 918 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 919 920 PetscFunctionBegin; 921 PetscCall(DMGetDimension(dm, &dim)); 922 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 923 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 924 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 925 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 926 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 927 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 928 PetscCall(VecGetArrayRead(coordinates, &a)); 929 name[0] = "vertex"; 930 name[1] = "edge"; 931 name[dim - 1] = "face"; 932 name[dim] = "cell"; 933 for (c = cStart; c < cEnd; ++c) { 934 PetscInt *closure = NULL; 935 PetscInt closureSize, cl, ct; 936 937 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 938 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 939 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 940 PetscCall(PetscViewerASCIIPushTab(viewer)); 941 for (cl = 0; cl < closureSize * 2; cl += 2) { 942 PetscInt point = closure[cl], depth, dof, off, d, p; 943 944 if ((point < pStart) || (point >= pEnd)) continue; 945 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 946 if (!dof) continue; 947 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 948 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 949 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 950 for (p = 0; p < dof / dim; ++p) { 951 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 952 for (d = 0; d < dim; ++d) { 953 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 955 } 956 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 957 } 958 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 959 } 960 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 961 PetscCall(PetscViewerASCIIPopTab(viewer)); 962 } 963 PetscCall(VecRestoreArrayRead(coordinates, &a)); 964 PetscFunctionReturn(PETSC_SUCCESS); 965 } 966 967 typedef enum { 968 CS_CARTESIAN, 969 CS_POLAR, 970 CS_CYLINDRICAL, 971 CS_SPHERICAL 972 } CoordSystem; 973 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 974 975 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 976 { 977 PetscInt i; 978 979 PetscFunctionBegin; 980 if (dim > 3) { 981 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 982 } else { 983 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 984 985 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 986 switch (cs) { 987 case CS_CARTESIAN: 988 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 989 break; 990 case CS_POLAR: 991 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 992 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 993 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 994 break; 995 case CS_CYLINDRICAL: 996 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 997 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 998 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 999 trcoords[2] = coords[2]; 1000 break; 1001 case CS_SPHERICAL: 1002 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 1003 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 1004 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 1005 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 1006 break; 1007 } 1008 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 1009 } 1010 PetscFunctionReturn(PETSC_SUCCESS); 1011 } 1012 1013 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 1014 { 1015 DM_Plex *mesh = (DM_Plex *)dm->data; 1016 DM cdm, cdmCell; 1017 PetscSection coordSection, coordSectionCell; 1018 Vec coordinates, coordinatesCell; 1019 PetscViewerFormat format; 1020 1021 PetscFunctionBegin; 1022 PetscCall(PetscViewerGetFormat(viewer, &format)); 1023 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1024 const char *name; 1025 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1026 PetscInt pStart, pEnd, p, numLabels, l; 1027 PetscMPIInt rank, size; 1028 1029 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1030 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1031 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1032 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1033 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1034 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1035 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1036 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1037 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1038 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1039 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1040 PetscCall(DMGetDimension(dm, &dim)); 1041 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1042 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1043 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1044 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1045 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1046 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1047 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1048 for (p = pStart; p < pEnd; ++p) { 1049 PetscInt dof, off, s; 1050 1051 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1052 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1053 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1054 } 1055 PetscCall(PetscViewerFlush(viewer)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1057 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1058 for (p = pStart; p < pEnd; ++p) { 1059 PetscInt dof, off, c; 1060 1061 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1062 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1063 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 1064 } 1065 PetscCall(PetscViewerFlush(viewer)); 1066 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1067 if (coordSection && coordinates) { 1068 CoordSystem cs = CS_CARTESIAN; 1069 const PetscScalar *array, *arrayCell = NULL; 1070 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1071 PetscMPIInt rank; 1072 const char *name; 1073 1074 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1075 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1076 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1077 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1078 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1079 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1080 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1081 pStart = PetscMin(pvStart, pcStart); 1082 pEnd = PetscMax(pvEnd, pcEnd); 1083 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1084 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1085 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1086 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1087 1088 PetscCall(VecGetArrayRead(coordinates, &array)); 1089 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1090 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1091 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1092 for (p = pStart; p < pEnd; ++p) { 1093 PetscInt dof, off; 1094 1095 if (p >= pvStart && p < pvEnd) { 1096 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1097 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1098 if (dof) { 1099 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1100 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1101 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1102 } 1103 } 1104 if (cdmCell && p >= pcStart && p < pcEnd) { 1105 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1106 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1107 if (dof) { 1108 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1109 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1110 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1111 } 1112 } 1113 } 1114 PetscCall(PetscViewerFlush(viewer)); 1115 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1116 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1117 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1118 } 1119 PetscCall(DMGetNumLabels(dm, &numLabels)); 1120 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1121 for (l = 0; l < numLabels; ++l) { 1122 DMLabel label; 1123 PetscBool isdepth; 1124 const char *name; 1125 1126 PetscCall(DMGetLabelName(dm, l, &name)); 1127 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1128 if (isdepth) continue; 1129 PetscCall(DMGetLabel(dm, name, &label)); 1130 PetscCall(DMLabelView(label, viewer)); 1131 } 1132 if (size > 1) { 1133 PetscSF sf; 1134 1135 PetscCall(DMGetPointSF(dm, &sf)); 1136 PetscCall(PetscSFView(sf, viewer)); 1137 } 1138 if (mesh->periodic.face_sfs) 1139 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1140 PetscCall(PetscViewerFlush(viewer)); 1141 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1142 const char *name, *color; 1143 const char *defcolors[3] = {"gray", "orange", "green"}; 1144 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1145 char lname[PETSC_MAX_PATH_LEN]; 1146 PetscReal scale = 2.0; 1147 PetscReal tikzscale = 1.0; 1148 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1149 double tcoords[3]; 1150 PetscScalar *coords; 1151 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 1152 PetscMPIInt rank, size; 1153 char **names, **colors, **lcolors; 1154 PetscBool flg, lflg; 1155 PetscBT wp = NULL; 1156 PetscInt pEnd, pStart; 1157 1158 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1159 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1160 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1161 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1162 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1163 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1164 PetscCall(DMGetDimension(dm, &dim)); 1165 PetscCall(DMPlexGetDepth(dm, &depth)); 1166 PetscCall(DMGetNumLabels(dm, &numLabels)); 1167 numLabels = PetscMax(numLabels, 10); 1168 numColors = 10; 1169 numLColors = 10; 1170 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1171 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1172 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1173 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1174 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1175 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1176 n = 4; 1177 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1178 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1179 n = 4; 1180 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1181 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1182 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1183 if (!useLabels) numLabels = 0; 1184 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1185 if (!useColors) { 1186 numColors = 3; 1187 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1188 } 1189 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1190 if (!useColors) { 1191 numLColors = 4; 1192 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1193 } 1194 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1195 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1196 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1197 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1198 if (depth < dim) plotEdges = PETSC_FALSE; 1199 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1200 1201 /* filter points with labelvalue != labeldefaultvalue */ 1202 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1203 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1204 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1205 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1206 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1207 if (lflg) { 1208 DMLabel lbl; 1209 1210 PetscCall(DMGetLabel(dm, lname, &lbl)); 1211 if (lbl) { 1212 PetscInt val, defval; 1213 1214 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1215 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1216 for (c = pStart; c < pEnd; c++) { 1217 PetscInt *closure = NULL; 1218 PetscInt closureSize; 1219 1220 PetscCall(DMLabelGetValue(lbl, c, &val)); 1221 if (val == defval) continue; 1222 1223 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1224 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1225 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1226 } 1227 } 1228 } 1229 1230 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1231 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1232 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1234 \\documentclass[tikz]{standalone}\n\n\ 1235 \\usepackage{pgflibraryshapes}\n\ 1236 \\usetikzlibrary{backgrounds}\n\ 1237 \\usetikzlibrary{arrows}\n\ 1238 \\begin{document}\n")); 1239 if (size > 1) { 1240 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1241 for (p = 0; p < size; ++p) { 1242 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1243 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1244 } 1245 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1246 } 1247 if (drawHasse) { 1248 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1249 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1258 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1264 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1265 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1266 } 1267 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1268 1269 /* Plot vertices */ 1270 PetscCall(VecGetArray(coordinates, &coords)); 1271 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1272 for (v = vStart; v < vEnd; ++v) { 1273 PetscInt off, dof, d; 1274 PetscBool isLabeled = PETSC_FALSE; 1275 1276 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1277 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1278 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1280 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1281 for (d = 0; d < dof; ++d) { 1282 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1283 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1284 } 1285 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1286 if (dim == 3) { 1287 PetscReal tmp = tcoords[1]; 1288 tcoords[1] = tcoords[2]; 1289 tcoords[2] = -tmp; 1290 } 1291 for (d = 0; d < dof; ++d) { 1292 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1293 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1294 } 1295 if (drawHasse) color = colors[0 % numColors]; 1296 else color = colors[rank % numColors]; 1297 for (l = 0; l < numLabels; ++l) { 1298 PetscInt val; 1299 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1300 if (val >= 0) { 1301 color = lcolors[l % numLColors]; 1302 isLabeled = PETSC_TRUE; 1303 break; 1304 } 1305 } 1306 if (drawNumbers[0]) { 1307 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1308 } else if (drawColors[0]) { 1309 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1310 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1311 } 1312 PetscCall(VecRestoreArray(coordinates, &coords)); 1313 PetscCall(PetscViewerFlush(viewer)); 1314 /* Plot edges */ 1315 if (plotEdges) { 1316 PetscCall(VecGetArray(coordinates, &coords)); 1317 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1318 for (e = eStart; e < eEnd; ++e) { 1319 const PetscInt *cone; 1320 PetscInt coneSize, offA, offB, dof, d; 1321 1322 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1323 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1324 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1325 PetscCall(DMPlexGetCone(dm, e, &cone)); 1326 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1327 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1328 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1329 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1330 for (d = 0; d < dof; ++d) { 1331 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1332 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1333 } 1334 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1335 if (dim == 3) { 1336 PetscReal tmp = tcoords[1]; 1337 tcoords[1] = tcoords[2]; 1338 tcoords[2] = -tmp; 1339 } 1340 for (d = 0; d < dof; ++d) { 1341 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1342 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1343 } 1344 if (drawHasse) color = colors[1 % numColors]; 1345 else color = colors[rank % numColors]; 1346 for (l = 0; l < numLabels; ++l) { 1347 PetscInt val; 1348 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1349 if (val >= 0) { 1350 color = lcolors[l % numLColors]; 1351 break; 1352 } 1353 } 1354 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1355 } 1356 PetscCall(VecRestoreArray(coordinates, &coords)); 1357 PetscCall(PetscViewerFlush(viewer)); 1358 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1359 } 1360 /* Plot cells */ 1361 if (dim == 3 || !drawNumbers[1]) { 1362 for (e = eStart; e < eEnd; ++e) { 1363 const PetscInt *cone; 1364 1365 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1366 color = colors[rank % numColors]; 1367 for (l = 0; l < numLabels; ++l) { 1368 PetscInt val; 1369 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1370 if (val >= 0) { 1371 color = lcolors[l % numLColors]; 1372 break; 1373 } 1374 } 1375 PetscCall(DMPlexGetCone(dm, e, &cone)); 1376 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1377 } 1378 } else { 1379 DMPolytopeType ct; 1380 1381 /* Drawing a 2D polygon */ 1382 for (c = cStart; c < cEnd; ++c) { 1383 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1384 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1385 if (DMPolytopeTypeIsHybrid(ct)) { 1386 const PetscInt *cone; 1387 PetscInt coneSize, e; 1388 1389 PetscCall(DMPlexGetCone(dm, c, &cone)); 1390 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1391 for (e = 0; e < coneSize; ++e) { 1392 const PetscInt *econe; 1393 1394 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1395 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1396 } 1397 } else { 1398 PetscInt *closure = NULL; 1399 PetscInt closureSize, Nv = 0, v; 1400 1401 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1402 for (p = 0; p < closureSize * 2; p += 2) { 1403 const PetscInt point = closure[p]; 1404 1405 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1406 } 1407 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1408 for (v = 0; v <= Nv; ++v) { 1409 const PetscInt vertex = closure[v % Nv]; 1410 1411 if (v > 0) { 1412 if (plotEdges) { 1413 const PetscInt *edge; 1414 PetscInt endpoints[2], ne; 1415 1416 endpoints[0] = closure[v - 1]; 1417 endpoints[1] = vertex; 1418 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1419 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1420 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1421 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1422 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1423 } 1424 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1425 } 1426 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1427 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1428 } 1429 } 1430 } 1431 for (c = cStart; c < cEnd; ++c) { 1432 double ccoords[3] = {0.0, 0.0, 0.0}; 1433 PetscBool isLabeled = PETSC_FALSE; 1434 PetscScalar *cellCoords = NULL; 1435 const PetscScalar *array; 1436 PetscInt numCoords, cdim, d; 1437 PetscBool isDG; 1438 1439 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1440 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1441 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1442 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1443 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1444 for (p = 0; p < numCoords / cdim; ++p) { 1445 for (d = 0; d < cdim; ++d) { 1446 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1447 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1448 } 1449 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1450 if (cdim == 3) { 1451 PetscReal tmp = tcoords[1]; 1452 tcoords[1] = tcoords[2]; 1453 tcoords[2] = -tmp; 1454 } 1455 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1456 } 1457 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1458 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1459 for (d = 0; d < cdim; ++d) { 1460 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1461 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1462 } 1463 if (drawHasse) color = colors[depth % numColors]; 1464 else color = colors[rank % numColors]; 1465 for (l = 0; l < numLabels; ++l) { 1466 PetscInt val; 1467 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1468 if (val >= 0) { 1469 color = lcolors[l % numLColors]; 1470 isLabeled = PETSC_TRUE; 1471 break; 1472 } 1473 } 1474 if (drawNumbers[dim]) { 1475 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1476 } else if (drawColors[dim]) { 1477 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1478 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1479 } 1480 if (drawHasse) { 1481 int height = 0; 1482 1483 color = colors[depth % numColors]; 1484 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1485 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1486 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1487 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1489 1490 if (depth > 2) { 1491 color = colors[1 % numColors]; 1492 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1493 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1494 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1495 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1496 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1497 } 1498 1499 color = colors[1 % numColors]; 1500 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1502 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1503 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1504 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1505 1506 color = colors[0 % numColors]; 1507 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1510 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1511 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1512 1513 for (p = pStart; p < pEnd; ++p) { 1514 const PetscInt *cone; 1515 PetscInt coneSize, cp; 1516 1517 PetscCall(DMPlexGetCone(dm, p, &cone)); 1518 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1519 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1520 } 1521 } 1522 PetscCall(PetscViewerFlush(viewer)); 1523 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1524 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1525 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1526 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1527 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1528 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1529 PetscCall(PetscFree3(names, colors, lcolors)); 1530 PetscCall(PetscBTDestroy(&wp)); 1531 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1532 Vec cown, acown; 1533 VecScatter sct; 1534 ISLocalToGlobalMapping g2l; 1535 IS gid, acis; 1536 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1537 MPI_Group ggroup, ngroup; 1538 PetscScalar *array, nid; 1539 const PetscInt *idxs; 1540 PetscInt *idxs2, *start, *adjacency, *work; 1541 PetscInt64 lm[3], gm[3]; 1542 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1543 PetscMPIInt d1, d2, rank; 1544 1545 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1546 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1547 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1548 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1549 #endif 1550 if (ncomm != MPI_COMM_NULL) { 1551 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1552 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1553 d1 = 0; 1554 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1555 nid = d2; 1556 PetscCallMPI(MPI_Group_free(&ggroup)); 1557 PetscCallMPI(MPI_Group_free(&ngroup)); 1558 PetscCallMPI(MPI_Comm_free(&ncomm)); 1559 } else nid = 0.0; 1560 1561 /* Get connectivity */ 1562 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1563 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1564 1565 /* filter overlapped local cells */ 1566 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1567 PetscCall(ISGetIndices(gid, &idxs)); 1568 PetscCall(ISGetLocalSize(gid, &cum)); 1569 PetscCall(PetscMalloc1(cum, &idxs2)); 1570 for (c = cStart, cum = 0; c < cEnd; c++) { 1571 if (idxs[c - cStart] < 0) continue; 1572 idxs2[cum++] = idxs[c - cStart]; 1573 } 1574 PetscCall(ISRestoreIndices(gid, &idxs)); 1575 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1576 PetscCall(ISDestroy(&gid)); 1577 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1578 1579 /* support for node-aware cell locality */ 1580 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1581 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1582 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1583 PetscCall(VecGetArray(cown, &array)); 1584 for (c = 0; c < numVertices; c++) array[c] = nid; 1585 PetscCall(VecRestoreArray(cown, &array)); 1586 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1587 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1588 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1589 PetscCall(ISDestroy(&acis)); 1590 PetscCall(VecScatterDestroy(&sct)); 1591 PetscCall(VecDestroy(&cown)); 1592 1593 /* compute edgeCut */ 1594 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1595 PetscCall(PetscMalloc1(cum, &work)); 1596 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1597 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1598 PetscCall(ISDestroy(&gid)); 1599 PetscCall(VecGetArray(acown, &array)); 1600 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1601 PetscInt totl; 1602 1603 totl = start[c + 1] - start[c]; 1604 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1605 for (i = 0; i < totl; i++) { 1606 if (work[i] < 0) { 1607 ect += 1; 1608 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1609 } 1610 } 1611 } 1612 PetscCall(PetscFree(work)); 1613 PetscCall(VecRestoreArray(acown, &array)); 1614 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1615 lm[1] = -numVertices; 1616 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1617 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1618 lm[0] = ect; /* edgeCut */ 1619 lm[1] = ectn; /* node-aware edgeCut */ 1620 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1621 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1622 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1623 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1624 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1625 #else 1626 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1627 #endif 1628 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1629 PetscCall(PetscFree(start)); 1630 PetscCall(PetscFree(adjacency)); 1631 PetscCall(VecDestroy(&acown)); 1632 } else { 1633 const char *name; 1634 PetscInt *sizes, *hybsizes, *ghostsizes; 1635 PetscInt locDepth, depth, cellHeight, dim, d; 1636 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1637 PetscInt numLabels, l, maxSize = 17; 1638 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1639 MPI_Comm comm; 1640 PetscMPIInt size, rank; 1641 1642 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1643 PetscCallMPI(MPI_Comm_size(comm, &size)); 1644 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1645 PetscCall(DMGetDimension(dm, &dim)); 1646 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1647 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1648 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1649 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1650 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1651 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1652 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1653 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1654 gcNum = gcEnd - gcStart; 1655 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1656 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1657 for (d = 0; d <= depth; d++) { 1658 PetscInt Nc[2] = {0, 0}, ict; 1659 1660 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1661 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1662 ict = ct0; 1663 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1664 ct0 = (DMPolytopeType)ict; 1665 for (p = pStart; p < pEnd; ++p) { 1666 DMPolytopeType ct; 1667 1668 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1669 if (ct == ct0) ++Nc[0]; 1670 else ++Nc[1]; 1671 } 1672 if (size < maxSize) { 1673 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1674 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1675 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1676 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1677 for (p = 0; p < size; ++p) { 1678 if (rank == 0) { 1679 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1680 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1681 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1682 } 1683 } 1684 } else { 1685 PetscInt locMinMax[2]; 1686 1687 locMinMax[0] = Nc[0] + Nc[1]; 1688 locMinMax[1] = Nc[0] + Nc[1]; 1689 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1690 locMinMax[0] = Nc[1]; 1691 locMinMax[1] = Nc[1]; 1692 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1693 if (d == depth) { 1694 locMinMax[0] = gcNum; 1695 locMinMax[1] = gcNum; 1696 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1697 } 1698 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1699 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1700 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1701 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1702 } 1703 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1704 } 1705 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1706 { 1707 const PetscReal *maxCell; 1708 const PetscReal *L; 1709 PetscBool localized; 1710 1711 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1712 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1713 if (L || localized) { 1714 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1715 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1716 if (L) { 1717 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1718 for (d = 0; d < dim; ++d) { 1719 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1720 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1721 } 1722 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1723 } 1724 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1725 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1726 } 1727 } 1728 PetscCall(DMGetNumLabels(dm, &numLabels)); 1729 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1730 for (l = 0; l < numLabels; ++l) { 1731 DMLabel label; 1732 const char *name; 1733 PetscInt *values; 1734 PetscInt numValues, v; 1735 1736 PetscCall(DMGetLabelName(dm, l, &name)); 1737 PetscCall(DMGetLabel(dm, name, &label)); 1738 PetscCall(DMLabelGetNumValues(label, &numValues)); 1739 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1740 1741 { // Extract array of DMLabel values so it can be sorted 1742 IS is_values; 1743 const PetscInt *is_values_local = NULL; 1744 1745 PetscCall(DMLabelGetValueIS(label, &is_values)); 1746 PetscCall(ISGetIndices(is_values, &is_values_local)); 1747 PetscCall(PetscMalloc1(numValues, &values)); 1748 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1749 PetscCall(PetscSortInt(numValues, values)); 1750 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1751 PetscCall(ISDestroy(&is_values)); 1752 } 1753 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1754 for (v = 0; v < numValues; ++v) { 1755 PetscInt size; 1756 1757 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1758 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1759 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1760 } 1761 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1762 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1763 PetscCall(PetscFree(values)); 1764 } 1765 { 1766 char **labelNames; 1767 PetscInt Nl = numLabels; 1768 PetscBool flg; 1769 1770 PetscCall(PetscMalloc1(Nl, &labelNames)); 1771 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1772 for (l = 0; l < Nl; ++l) { 1773 DMLabel label; 1774 1775 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1776 if (flg) { 1777 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1778 PetscCall(DMLabelView(label, viewer)); 1779 } 1780 PetscCall(PetscFree(labelNames[l])); 1781 } 1782 PetscCall(PetscFree(labelNames)); 1783 } 1784 /* If no fields are specified, people do not want to see adjacency */ 1785 if (dm->Nf) { 1786 PetscInt f; 1787 1788 for (f = 0; f < dm->Nf; ++f) { 1789 const char *name; 1790 1791 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1792 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1793 PetscCall(PetscViewerASCIIPushTab(viewer)); 1794 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1795 if (dm->fields[f].adjacency[0]) { 1796 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1797 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1798 } else { 1799 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1800 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1801 } 1802 PetscCall(PetscViewerASCIIPopTab(viewer)); 1803 } 1804 } 1805 DMPlexTransform tr; 1806 1807 PetscCall(DMPlexGetTransform(dm, &tr)); 1808 if (tr) { 1809 PetscCall(PetscViewerASCIIPushTab(viewer)); 1810 PetscCall(PetscViewerASCIIPrintf(viewer, "Created using transform:\n")); 1811 PetscCall(DMPlexTransformView(tr, viewer)); 1812 PetscCall(PetscViewerASCIIPopTab(viewer)); 1813 } 1814 PetscCall(DMGetCoarseDM(dm, &cdm)); 1815 if (cdm) { 1816 PetscCall(PetscViewerASCIIPushTab(viewer)); 1817 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1818 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1819 PetscCall(PetscViewerASCIIPopTab(viewer)); 1820 } 1821 } 1822 PetscFunctionReturn(PETSC_SUCCESS); 1823 } 1824 1825 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt lC, PetscInt cC, PetscInt cell, const PetscScalar coords[]) 1826 { 1827 DMPolytopeType ct; 1828 PetscMPIInt rank; 1829 PetscInt cdim; 1830 int lineColor, cellColor; 1831 1832 PetscFunctionBegin; 1833 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1834 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1835 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1836 lineColor = (int)(lC < 0 ? PETSC_DRAW_BLACK : lC); 1837 cellColor = (int)(cC < 0 ? PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2 : cC); 1838 switch (ct) { 1839 case DM_POLYTOPE_SEGMENT: 1840 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1841 switch (cdim) { 1842 case 1: { 1843 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1844 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1845 1846 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, lineColor)); 1847 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, lineColor)); 1848 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, lineColor)); 1849 } break; 1850 case 2: { 1851 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1852 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1853 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1854 1855 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1856 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, lineColor)); 1857 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, lineColor)); 1858 } break; 1859 default: 1860 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1861 } 1862 break; 1863 case DM_POLYTOPE_TRIANGLE: 1864 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1865 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1866 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1867 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1868 break; 1869 case DM_POLYTOPE_QUADRILATERAL: 1870 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1871 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), cellColor, cellColor, cellColor)); 1872 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1873 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1874 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor)); 1875 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1876 break; 1877 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1878 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1879 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1880 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1881 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor)); 1882 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1883 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1884 break; 1885 case DM_POLYTOPE_FV_GHOST: 1886 break; 1887 default: 1888 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1889 } 1890 PetscFunctionReturn(PETSC_SUCCESS); 1891 } 1892 1893 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1894 { 1895 PetscReal centroid[2] = {0., 0.}; 1896 PetscMPIInt rank; 1897 PetscMPIInt fillColor; 1898 1899 PetscFunctionBegin; 1900 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1901 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1902 for (PetscInt v = 0; v < Nv; ++v) { 1903 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1904 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1905 } 1906 for (PetscInt e = 0; e < Nv; ++e) { 1907 refCoords[0] = refVertices[e * 2 + 0]; 1908 refCoords[1] = refVertices[e * 2 + 1]; 1909 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1910 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1911 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1912 } 1913 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1914 for (PetscInt d = 0; d < edgeDiv; ++d) { 1915 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)); 1916 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1917 } 1918 } 1919 PetscFunctionReturn(PETSC_SUCCESS); 1920 } 1921 1922 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1923 { 1924 DMPolytopeType ct; 1925 1926 PetscFunctionBegin; 1927 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1928 switch (ct) { 1929 case DM_POLYTOPE_TRIANGLE: { 1930 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1931 1932 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1933 } break; 1934 case DM_POLYTOPE_QUADRILATERAL: { 1935 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1936 1937 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1938 } break; 1939 default: 1940 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1941 } 1942 PetscFunctionReturn(PETSC_SUCCESS); 1943 } 1944 1945 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1946 { 1947 PetscDraw draw; 1948 DM cdm; 1949 PetscSection coordSection; 1950 Vec coordinates; 1951 PetscReal xyl[3], xyr[3]; 1952 PetscReal *refCoords, *edgeCoords; 1953 PetscBool isnull, drawAffine; 1954 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv, lineColor = PETSC_DETERMINE, cellColor = PETSC_DETERMINE; 1955 1956 PetscFunctionBegin; 1957 PetscCall(DMGetCoordinateDim(dm, &dim)); 1958 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1959 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1960 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1961 edgeDiv = cDegree + 1; 1962 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_line_color", &lineColor, NULL)); 1963 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_cell_color", &cellColor, NULL)); 1964 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1965 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1966 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1967 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1968 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1969 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1970 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1971 1972 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1973 PetscCall(PetscDrawIsNull(draw, &isnull)); 1974 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1975 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1976 1977 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1978 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1979 PetscCall(PetscDrawClear(draw)); 1980 1981 for (c = cStart; c < cEnd; ++c) { 1982 PetscScalar *coords = NULL; 1983 const PetscScalar *coords_arr; 1984 PetscInt numCoords; 1985 PetscBool isDG; 1986 1987 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1988 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, lineColor, cellColor, c, coords)); 1989 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1990 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1991 } 1992 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1993 PetscCall(PetscDrawFlush(draw)); 1994 PetscCall(PetscDrawPause(draw)); 1995 PetscCall(PetscDrawSave(draw)); 1996 PetscFunctionReturn(PETSC_SUCCESS); 1997 } 1998 1999 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 2000 { 2001 DM odm = dm, rdm = dm, cdm; 2002 PetscFE fe; 2003 PetscSpace sp; 2004 PetscClassId id; 2005 PetscInt degree; 2006 PetscBool hoView = PETSC_TRUE; 2007 2008 PetscFunctionBegin; 2009 PetscObjectOptionsBegin((PetscObject)dm); 2010 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 2011 PetscOptionsEnd(); 2012 PetscCall(PetscObjectReference((PetscObject)dm)); 2013 *hdm = dm; 2014 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 2015 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2016 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 2017 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 2018 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 2019 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 2020 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 2021 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 2022 DM cdm, rcdm; 2023 Mat In; 2024 Vec cl, rcl; 2025 2026 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 2027 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, PETSC_FALSE)); 2028 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 2029 PetscCall(DMGetCoordinateDM(odm, &cdm)); 2030 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 2031 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 2032 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 2033 PetscCall(DMSetCoarseDM(rcdm, cdm)); 2034 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 2035 PetscCall(MatMult(In, cl, rcl)); 2036 PetscCall(MatDestroy(&In)); 2037 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 2038 PetscCall(DMDestroy(&odm)); 2039 odm = rdm; 2040 } 2041 *hdm = rdm; 2042 PetscFunctionReturn(PETSC_SUCCESS); 2043 } 2044 2045 #if defined(PETSC_HAVE_EXODUSII) 2046 #include <exodusII.h> 2047 #include <petscviewerexodusii.h> 2048 #endif 2049 2050 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 2051 { 2052 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 2053 char name[PETSC_MAX_PATH_LEN]; 2054 2055 PetscFunctionBegin; 2056 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2057 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2058 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 2059 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2060 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2061 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2062 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 2063 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 2064 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 2065 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2066 if (iascii) { 2067 PetscViewerFormat format; 2068 PetscCall(PetscViewerGetFormat(viewer, &format)); 2069 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 2070 else PetscCall(DMPlexView_Ascii(dm, viewer)); 2071 } else if (ishdf5) { 2072 #if defined(PETSC_HAVE_HDF5) 2073 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 2074 #else 2075 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2076 #endif 2077 } else if (isvtk) { 2078 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2079 } else if (isdraw) { 2080 DM hdm; 2081 2082 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2083 PetscCall(DMPlexView_Draw(hdm, viewer)); 2084 PetscCall(DMDestroy(&hdm)); 2085 } else if (isglvis) { 2086 PetscCall(DMPlexView_GLVis(dm, viewer)); 2087 #if defined(PETSC_HAVE_EXODUSII) 2088 } else if (isexodus) { 2089 /* 2090 exodusII requires that all sets be part of exactly one cell set. 2091 If the dm does not have a "Cell Sets" label defined, we create one 2092 with ID 1, containing all cells. 2093 Note that if the Cell Sets label is defined but does not cover all cells, 2094 we may still have a problem. This should probably be checked here or in the viewer; 2095 */ 2096 PetscInt numCS; 2097 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2098 if (!numCS) { 2099 PetscInt cStart, cEnd, c; 2100 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2101 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2102 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2103 } 2104 PetscCall(DMView_PlexExodusII(dm, viewer)); 2105 #endif 2106 #if defined(PETSC_HAVE_CGNS) 2107 } else if (iscgns) { 2108 PetscCall(DMView_PlexCGNS(dm, viewer)); 2109 #endif 2110 } else if (ispython) { 2111 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2112 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2113 /* Optionally view the partition */ 2114 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2115 if (flg) { 2116 Vec ranks; 2117 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2118 PetscCall(VecView(ranks, viewer)); 2119 PetscCall(VecDestroy(&ranks)); 2120 } 2121 /* Optionally view a label */ 2122 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2123 if (flg) { 2124 DMLabel label; 2125 Vec val; 2126 2127 PetscCall(DMGetLabel(dm, name, &label)); 2128 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2129 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2130 PetscCall(VecView(val, viewer)); 2131 PetscCall(VecDestroy(&val)); 2132 } 2133 PetscFunctionReturn(PETSC_SUCCESS); 2134 } 2135 2136 /*@ 2137 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2138 2139 Collective 2140 2141 Input Parameters: 2142 + dm - The `DM` whose topology is to be saved 2143 - viewer - The `PetscViewer` to save it in 2144 2145 Level: advanced 2146 2147 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2148 @*/ 2149 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2150 { 2151 PetscBool ishdf5; 2152 2153 PetscFunctionBegin; 2154 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2155 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2156 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2157 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2158 if (ishdf5) { 2159 #if defined(PETSC_HAVE_HDF5) 2160 PetscViewerFormat format; 2161 PetscCall(PetscViewerGetFormat(viewer, &format)); 2162 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2163 IS globalPointNumbering; 2164 2165 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2166 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2167 PetscCall(ISDestroy(&globalPointNumbering)); 2168 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2169 #else 2170 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2171 #endif 2172 } 2173 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2174 PetscFunctionReturn(PETSC_SUCCESS); 2175 } 2176 2177 /*@ 2178 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2179 2180 Collective 2181 2182 Input Parameters: 2183 + dm - The `DM` whose coordinates are to be saved 2184 - viewer - The `PetscViewer` for saving 2185 2186 Level: advanced 2187 2188 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2189 @*/ 2190 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2191 { 2192 PetscBool ishdf5; 2193 2194 PetscFunctionBegin; 2195 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2196 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2197 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2198 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2199 if (ishdf5) { 2200 #if defined(PETSC_HAVE_HDF5) 2201 PetscViewerFormat format; 2202 PetscCall(PetscViewerGetFormat(viewer, &format)); 2203 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2204 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2205 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2206 #else 2207 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2208 #endif 2209 } 2210 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2211 PetscFunctionReturn(PETSC_SUCCESS); 2212 } 2213 2214 /*@ 2215 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2216 2217 Collective 2218 2219 Input Parameters: 2220 + dm - The `DM` whose labels are to be saved 2221 - viewer - The `PetscViewer` for saving 2222 2223 Level: advanced 2224 2225 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2226 @*/ 2227 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2228 { 2229 PetscBool ishdf5; 2230 2231 PetscFunctionBegin; 2232 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2233 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2234 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2235 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2236 if (ishdf5) { 2237 #if defined(PETSC_HAVE_HDF5) 2238 IS globalPointNumbering; 2239 PetscViewerFormat format; 2240 2241 PetscCall(PetscViewerGetFormat(viewer, &format)); 2242 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2243 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2244 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2245 PetscCall(ISDestroy(&globalPointNumbering)); 2246 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2247 #else 2248 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2249 #endif 2250 } 2251 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2252 PetscFunctionReturn(PETSC_SUCCESS); 2253 } 2254 2255 /*@ 2256 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2257 2258 Collective 2259 2260 Input Parameters: 2261 + dm - The `DM` that contains the topology on which the section to be saved is defined 2262 . viewer - The `PetscViewer` for saving 2263 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2264 2265 Level: advanced 2266 2267 Notes: 2268 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. 2269 2270 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. 2271 2272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2273 @*/ 2274 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2275 { 2276 PetscBool ishdf5; 2277 2278 PetscFunctionBegin; 2279 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2280 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2281 if (!sectiondm) sectiondm = dm; 2282 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2283 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2284 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2285 if (ishdf5) { 2286 #if defined(PETSC_HAVE_HDF5) 2287 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2288 #else 2289 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2290 #endif 2291 } 2292 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2293 PetscFunctionReturn(PETSC_SUCCESS); 2294 } 2295 2296 /*@ 2297 DMPlexGlobalVectorView - Saves a global vector 2298 2299 Collective 2300 2301 Input Parameters: 2302 + dm - The `DM` that represents the topology 2303 . viewer - The `PetscViewer` to save data with 2304 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2305 - vec - The global vector to be saved 2306 2307 Level: advanced 2308 2309 Notes: 2310 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. 2311 2312 Calling sequence: 2313 .vb 2314 DMCreate(PETSC_COMM_WORLD, &dm); 2315 DMSetType(dm, DMPLEX); 2316 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2317 DMClone(dm, §iondm); 2318 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2319 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2320 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2321 PetscSectionSetChart(section, pStart, pEnd); 2322 PetscSectionSetUp(section); 2323 DMSetLocalSection(sectiondm, section); 2324 PetscSectionDestroy(§ion); 2325 DMGetGlobalVector(sectiondm, &vec); 2326 PetscObjectSetName((PetscObject)vec, "vec_name"); 2327 DMPlexTopologyView(dm, viewer); 2328 DMPlexSectionView(dm, viewer, sectiondm); 2329 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2330 DMRestoreGlobalVector(sectiondm, &vec); 2331 DMDestroy(§iondm); 2332 DMDestroy(&dm); 2333 .ve 2334 2335 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2336 @*/ 2337 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2338 { 2339 PetscBool ishdf5; 2340 2341 PetscFunctionBegin; 2342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2343 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2344 if (!sectiondm) sectiondm = dm; 2345 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2346 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2347 /* Check consistency */ 2348 { 2349 PetscSection section; 2350 PetscBool includesConstraints; 2351 PetscInt m, m1; 2352 2353 PetscCall(VecGetLocalSize(vec, &m1)); 2354 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2355 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2356 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2357 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2358 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2359 } 2360 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2361 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2362 if (ishdf5) { 2363 #if defined(PETSC_HAVE_HDF5) 2364 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2365 #else 2366 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2367 #endif 2368 } 2369 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2370 PetscFunctionReturn(PETSC_SUCCESS); 2371 } 2372 2373 /*@ 2374 DMPlexLocalVectorView - Saves a local vector 2375 2376 Collective 2377 2378 Input Parameters: 2379 + dm - The `DM` that represents the topology 2380 . viewer - The `PetscViewer` to save data with 2381 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2382 - vec - The local vector to be saved 2383 2384 Level: advanced 2385 2386 Note: 2387 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. 2388 2389 Calling sequence: 2390 .vb 2391 DMCreate(PETSC_COMM_WORLD, &dm); 2392 DMSetType(dm, DMPLEX); 2393 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2394 DMClone(dm, §iondm); 2395 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2396 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2397 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2398 PetscSectionSetChart(section, pStart, pEnd); 2399 PetscSectionSetUp(section); 2400 DMSetLocalSection(sectiondm, section); 2401 DMGetLocalVector(sectiondm, &vec); 2402 PetscObjectSetName((PetscObject)vec, "vec_name"); 2403 DMPlexTopologyView(dm, viewer); 2404 DMPlexSectionView(dm, viewer, sectiondm); 2405 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2406 DMRestoreLocalVector(sectiondm, &vec); 2407 DMDestroy(§iondm); 2408 DMDestroy(&dm); 2409 .ve 2410 2411 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2412 @*/ 2413 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2414 { 2415 PetscBool ishdf5; 2416 2417 PetscFunctionBegin; 2418 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2419 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2420 if (!sectiondm) sectiondm = dm; 2421 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2422 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2423 /* Check consistency */ 2424 { 2425 PetscSection section; 2426 PetscBool includesConstraints; 2427 PetscInt m, m1; 2428 2429 PetscCall(VecGetLocalSize(vec, &m1)); 2430 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2431 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2432 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2433 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2434 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2435 } 2436 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2437 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2438 if (ishdf5) { 2439 #if defined(PETSC_HAVE_HDF5) 2440 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2441 #else 2442 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2443 #endif 2444 } 2445 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2446 PetscFunctionReturn(PETSC_SUCCESS); 2447 } 2448 2449 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2450 { 2451 PetscBool ishdf5; 2452 2453 PetscFunctionBegin; 2454 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2455 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2456 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2457 if (ishdf5) { 2458 #if defined(PETSC_HAVE_HDF5) 2459 PetscViewerFormat format; 2460 PetscCall(PetscViewerGetFormat(viewer, &format)); 2461 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2462 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2463 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2464 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2465 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2466 PetscFunctionReturn(PETSC_SUCCESS); 2467 #else 2468 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2469 #endif 2470 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2471 } 2472 2473 /*@ 2474 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2475 2476 Collective 2477 2478 Input Parameters: 2479 + dm - The `DM` into which the topology is loaded 2480 - viewer - The `PetscViewer` for the saved topology 2481 2482 Output Parameter: 2483 . 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; 2484 `NULL` if unneeded 2485 2486 Level: advanced 2487 2488 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2489 `PetscViewer`, `PetscSF` 2490 @*/ 2491 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2492 { 2493 PetscBool ishdf5; 2494 2495 PetscFunctionBegin; 2496 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2497 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2498 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2499 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2500 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2501 if (ishdf5) { 2502 #if defined(PETSC_HAVE_HDF5) 2503 PetscViewerFormat format; 2504 PetscCall(PetscViewerGetFormat(viewer, &format)); 2505 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2506 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2507 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2508 #else 2509 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2510 #endif 2511 } 2512 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2513 PetscFunctionReturn(PETSC_SUCCESS); 2514 } 2515 2516 /*@ 2517 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2518 2519 Collective 2520 2521 Input Parameters: 2522 + dm - The `DM` into which the coordinates are loaded 2523 . viewer - The `PetscViewer` for the saved coordinates 2524 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2525 2526 Level: advanced 2527 2528 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2529 `PetscSF`, `PetscViewer` 2530 @*/ 2531 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2532 { 2533 PetscBool ishdf5; 2534 2535 PetscFunctionBegin; 2536 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2537 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2538 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2539 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2540 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2541 if (ishdf5) { 2542 #if defined(PETSC_HAVE_HDF5) 2543 PetscViewerFormat format; 2544 PetscCall(PetscViewerGetFormat(viewer, &format)); 2545 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2546 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2547 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2548 #else 2549 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2550 #endif 2551 } 2552 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2553 PetscFunctionReturn(PETSC_SUCCESS); 2554 } 2555 2556 /*@ 2557 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2558 2559 Collective 2560 2561 Input Parameters: 2562 + dm - The `DM` into which the labels are loaded 2563 . viewer - The `PetscViewer` for the saved labels 2564 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2565 2566 Level: advanced 2567 2568 Note: 2569 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2570 2571 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2572 `PetscSF`, `PetscViewer` 2573 @*/ 2574 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2575 { 2576 PetscBool ishdf5; 2577 2578 PetscFunctionBegin; 2579 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2580 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2581 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2582 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2583 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2584 if (ishdf5) { 2585 #if defined(PETSC_HAVE_HDF5) 2586 PetscViewerFormat format; 2587 2588 PetscCall(PetscViewerGetFormat(viewer, &format)); 2589 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2590 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2591 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2592 #else 2593 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2594 #endif 2595 } 2596 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2597 PetscFunctionReturn(PETSC_SUCCESS); 2598 } 2599 2600 /*@ 2601 DMPlexSectionLoad - Loads section into a `DMPLEX` 2602 2603 Collective 2604 2605 Input Parameters: 2606 + dm - The `DM` that represents the topology 2607 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2608 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2609 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2610 2611 Output Parameters: 2612 + 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) 2613 - 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) 2614 2615 Level: advanced 2616 2617 Notes: 2618 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. 2619 2620 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. 2621 2622 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. 2623 2624 Example using 2 processes: 2625 .vb 2626 NX (number of points on dm): 4 2627 sectionA : the on-disk section 2628 vecA : a vector associated with sectionA 2629 sectionB : sectiondm's local section constructed in this function 2630 vecB (local) : a vector associated with sectiondm's local section 2631 vecB (global) : a vector associated with sectiondm's global section 2632 2633 rank 0 rank 1 2634 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2635 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2636 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2637 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2638 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2639 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2640 sectionB->atlasDof : 1 0 1 | 1 3 2641 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2642 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2643 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2644 .ve 2645 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2646 2647 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2648 @*/ 2649 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, PeOp DM sectiondm, PetscSF globalToLocalPointSF, PeOp PetscSF *globalDofSF, PeOp PetscSF *localDofSF) 2650 { 2651 PetscBool ishdf5; 2652 2653 PetscFunctionBegin; 2654 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2655 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2656 if (!sectiondm) sectiondm = dm; 2657 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2658 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2659 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2660 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2661 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2662 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2663 if (ishdf5) { 2664 #if defined(PETSC_HAVE_HDF5) 2665 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2666 #else 2667 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2668 #endif 2669 } 2670 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2671 PetscFunctionReturn(PETSC_SUCCESS); 2672 } 2673 2674 /*@ 2675 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2676 2677 Collective 2678 2679 Input Parameters: 2680 + dm - The `DM` that represents the topology 2681 . viewer - The `PetscViewer` that represents the on-disk vector data 2682 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2683 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2684 - vec - The global vector to set values of 2685 2686 Level: advanced 2687 2688 Notes: 2689 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. 2690 2691 Calling sequence: 2692 .vb 2693 DMCreate(PETSC_COMM_WORLD, &dm); 2694 DMSetType(dm, DMPLEX); 2695 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2696 DMPlexTopologyLoad(dm, viewer, &sfX); 2697 DMClone(dm, §iondm); 2698 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2699 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2700 DMGetGlobalVector(sectiondm, &vec); 2701 PetscObjectSetName((PetscObject)vec, "vec_name"); 2702 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2703 DMRestoreGlobalVector(sectiondm, &vec); 2704 PetscSFDestroy(&gsf); 2705 PetscSFDestroy(&sfX); 2706 DMDestroy(§iondm); 2707 DMDestroy(&dm); 2708 .ve 2709 2710 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2711 `PetscSF`, `PetscViewer` 2712 @*/ 2713 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2714 { 2715 PetscBool ishdf5; 2716 2717 PetscFunctionBegin; 2718 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2719 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2720 if (!sectiondm) sectiondm = dm; 2721 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2722 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2723 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2724 /* Check consistency */ 2725 { 2726 PetscSection section; 2727 PetscBool includesConstraints; 2728 PetscInt m, m1; 2729 2730 PetscCall(VecGetLocalSize(vec, &m1)); 2731 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2732 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2733 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2734 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2735 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2736 } 2737 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2738 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2739 if (ishdf5) { 2740 #if defined(PETSC_HAVE_HDF5) 2741 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2742 #else 2743 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2744 #endif 2745 } 2746 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2747 PetscFunctionReturn(PETSC_SUCCESS); 2748 } 2749 2750 /*@ 2751 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2752 2753 Collective 2754 2755 Input Parameters: 2756 + dm - The `DM` that represents the topology 2757 . viewer - The `PetscViewer` that represents the on-disk vector data 2758 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2759 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2760 - vec - The local vector to set values of 2761 2762 Level: advanced 2763 2764 Notes: 2765 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. 2766 2767 Calling sequence: 2768 .vb 2769 DMCreate(PETSC_COMM_WORLD, &dm); 2770 DMSetType(dm, DMPLEX); 2771 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2772 DMPlexTopologyLoad(dm, viewer, &sfX); 2773 DMClone(dm, §iondm); 2774 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2775 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2776 DMGetLocalVector(sectiondm, &vec); 2777 PetscObjectSetName((PetscObject)vec, "vec_name"); 2778 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2779 DMRestoreLocalVector(sectiondm, &vec); 2780 PetscSFDestroy(&lsf); 2781 PetscSFDestroy(&sfX); 2782 DMDestroy(§iondm); 2783 DMDestroy(&dm); 2784 .ve 2785 2786 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2787 `PetscSF`, `PetscViewer` 2788 @*/ 2789 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2790 { 2791 PetscBool ishdf5; 2792 2793 PetscFunctionBegin; 2794 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2795 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2796 if (!sectiondm) sectiondm = dm; 2797 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2798 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2799 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2800 /* Check consistency */ 2801 { 2802 PetscSection section; 2803 PetscBool includesConstraints; 2804 PetscInt m, m1; 2805 2806 PetscCall(VecGetLocalSize(vec, &m1)); 2807 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2808 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2809 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2810 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2811 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2812 } 2813 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2814 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2815 if (ishdf5) { 2816 #if defined(PETSC_HAVE_HDF5) 2817 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2818 #else 2819 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2820 #endif 2821 } 2822 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2823 PetscFunctionReturn(PETSC_SUCCESS); 2824 } 2825 2826 PetscErrorCode DMDestroy_Plex(DM dm) 2827 { 2828 DM_Plex *mesh = (DM_Plex *)dm->data; 2829 2830 PetscFunctionBegin; 2831 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2832 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2833 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2834 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBounds_C", NULL)); 2835 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2836 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2837 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2838 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2839 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2840 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2841 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2842 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2843 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2844 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2845 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2846 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2847 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2848 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2849 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2850 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2851 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2852 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2853 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2854 PetscCall(PetscFree(mesh->cones)); 2855 PetscCall(PetscFree(mesh->coneOrientations)); 2856 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2857 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2858 PetscCall(PetscFree(mesh->supports)); 2859 PetscCall(PetscFree(mesh->cellTypes)); 2860 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2861 PetscCall(PetscFree(mesh->tetgenOpts)); 2862 PetscCall(PetscFree(mesh->triangleOpts)); 2863 PetscCall(PetscFree(mesh->transformType)); 2864 PetscCall(PetscFree(mesh->distributionName)); 2865 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2866 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2867 PetscCall(ISDestroy(&mesh->subpointIS)); 2868 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2869 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2870 if (mesh->periodic.face_sfs) { 2871 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2872 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2873 } 2874 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2875 if (mesh->periodic.periodic_points) { 2876 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2877 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2878 } 2879 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2880 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2881 PetscCall(ISDestroy(&mesh->anchorIS)); 2882 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2883 PetscCall(PetscFree(mesh->parents)); 2884 PetscCall(PetscFree(mesh->childIDs)); 2885 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2886 PetscCall(PetscFree(mesh->children)); 2887 PetscCall(DMDestroy(&mesh->referenceTree)); 2888 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2889 PetscCall(PetscFree(mesh->neighbors)); 2890 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2891 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2892 PetscCall(DMPlexTransformDestroy(&mesh->transform)); 2893 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2894 PetscCall(PetscFree(mesh)); 2895 PetscFunctionReturn(PETSC_SUCCESS); 2896 } 2897 2898 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2899 { 2900 PetscSection sectionGlobal, sectionLocal; 2901 PetscInt bs = -1, mbs; 2902 PetscInt localSize, localStart = 0; 2903 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2904 MatType mtype; 2905 ISLocalToGlobalMapping ltog; 2906 2907 PetscFunctionBegin; 2908 PetscCall(MatInitializePackage()); 2909 mtype = dm->mattype; 2910 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2911 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2912 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2913 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2914 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2915 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2916 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2917 PetscCall(MatSetType(*J, mtype)); 2918 PetscCall(MatSetFromOptions(*J)); 2919 PetscCall(MatGetBlockSize(*J, &mbs)); 2920 if (mbs > 1) bs = mbs; 2921 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2922 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2923 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2924 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2925 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2926 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2927 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2928 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2929 if (!isShell) { 2930 // There are three states with pblocks, since block starts can have no dofs: 2931 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2932 // TRUE) Block Start: The first entry in a block has been added 2933 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2934 PetscBT blst; 2935 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2936 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2937 const PetscInt *perm = NULL; 2938 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2939 PetscInt pStart, pEnd, dof, cdof, num_fields; 2940 2941 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2942 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2943 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2944 2945 PetscCall(PetscCalloc1(localSize, &pblocks)); 2946 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2947 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2948 // We need to process in the permuted order to get block sizes right 2949 for (PetscInt point = pStart; point < pEnd; ++point) { 2950 const PetscInt p = perm ? perm[point] : point; 2951 2952 switch (dm->blocking_type) { 2953 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2954 PetscInt bdof, offset; 2955 2956 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2957 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2958 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2959 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2960 if (dof > 0) { 2961 // State change 2962 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2963 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2964 2965 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2966 // Signal block concatenation 2967 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2968 } 2969 dof = dof < 0 ? -(dof + 1) : dof; 2970 bdof = cdof && (dof - cdof) ? 1 : dof; 2971 if (dof) { 2972 if (bs < 0) { 2973 bs = bdof; 2974 } else if (bs != bdof) { 2975 bs = 1; 2976 } 2977 } 2978 } break; 2979 case DM_BLOCKING_FIELD_NODE: { 2980 for (PetscInt field = 0; field < num_fields; field++) { 2981 PetscInt num_comp, bdof, offset; 2982 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2983 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2984 if (dof < 0) continue; 2985 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2986 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2987 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); 2988 PetscInt num_nodes = dof / num_comp; 2989 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2990 // Handle possibly constant block size (unlikely) 2991 bdof = cdof && (dof - cdof) ? 1 : dof; 2992 if (dof) { 2993 if (bs < 0) { 2994 bs = bdof; 2995 } else if (bs != bdof) { 2996 bs = 1; 2997 } 2998 } 2999 } 3000 } break; 3001 } 3002 } 3003 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 3004 /* Must have same blocksize on all procs (some might have no points) */ 3005 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 3006 bsLocal[1] = bs; 3007 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 3008 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 3009 else bs = bsMinMax[0]; 3010 bs = PetscMax(1, bs); 3011 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 3012 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 3013 PetscCall(MatSetBlockSize(*J, bs)); 3014 PetscCall(MatSetUp(*J)); 3015 } else { 3016 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 3017 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 3018 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 3019 } 3020 if (pblocks) { // Consolidate blocks 3021 PetscInt nblocks = 0; 3022 pblocks[0] = PetscAbs(pblocks[0]); 3023 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 3024 if (pblocks[i] == 0) continue; 3025 // Negative block size indicates the blocks should be concatenated 3026 if (pblocks[i] < 0) { 3027 pblocks[i] = -pblocks[i]; 3028 pblocks[nblocks - 1] += pblocks[i]; 3029 } else { 3030 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 3031 } 3032 for (PetscInt j = 1; j < pblocks[i]; j++) 3033 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); 3034 } 3035 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 3036 } 3037 PetscCall(PetscFree(pblocks)); 3038 } 3039 PetscCall(MatSetDM(*J, dm)); 3040 PetscFunctionReturn(PETSC_SUCCESS); 3041 } 3042 3043 /*@ 3044 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 3045 3046 Not Collective 3047 3048 Input Parameter: 3049 . dm - The `DMPLEX` 3050 3051 Output Parameter: 3052 . subsection - The subdomain section 3053 3054 Level: developer 3055 3056 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 3057 @*/ 3058 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 3059 { 3060 DM_Plex *mesh = (DM_Plex *)dm->data; 3061 3062 PetscFunctionBegin; 3063 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3064 if (!mesh->subdomainSection) { 3065 PetscSection section; 3066 PetscSF sf; 3067 3068 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 3069 PetscCall(DMGetLocalSection(dm, §ion)); 3070 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 3071 PetscCall(PetscSFDestroy(&sf)); 3072 } 3073 *subsection = mesh->subdomainSection; 3074 PetscFunctionReturn(PETSC_SUCCESS); 3075 } 3076 3077 /*@ 3078 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 3079 3080 Not Collective 3081 3082 Input Parameter: 3083 . dm - The `DMPLEX` 3084 3085 Output Parameters: 3086 + pStart - The first mesh point 3087 - pEnd - The upper bound for mesh points 3088 3089 Level: beginner 3090 3091 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3092 @*/ 3093 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3094 { 3095 DM_Plex *mesh = (DM_Plex *)dm->data; 3096 3097 PetscFunctionBegin; 3098 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3099 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3100 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3101 PetscFunctionReturn(PETSC_SUCCESS); 3102 } 3103 3104 /*@ 3105 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3106 3107 Not Collective 3108 3109 Input Parameters: 3110 + dm - The `DMPLEX` 3111 . pStart - The first mesh point 3112 - pEnd - The upper bound for mesh points 3113 3114 Level: beginner 3115 3116 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3117 @*/ 3118 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3119 { 3120 DM_Plex *mesh = (DM_Plex *)dm->data; 3121 3122 PetscFunctionBegin; 3123 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3124 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3125 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3126 PetscCall(PetscFree(mesh->cellTypes)); 3127 PetscFunctionReturn(PETSC_SUCCESS); 3128 } 3129 3130 /*@ 3131 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3132 3133 Not Collective 3134 3135 Input Parameters: 3136 + dm - The `DMPLEX` 3137 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3138 3139 Output Parameter: 3140 . size - The cone size for point `p` 3141 3142 Level: beginner 3143 3144 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3145 @*/ 3146 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3147 { 3148 DM_Plex *mesh = (DM_Plex *)dm->data; 3149 3150 PetscFunctionBegin; 3151 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3152 PetscAssertPointer(size, 3); 3153 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3154 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3155 PetscFunctionReturn(PETSC_SUCCESS); 3156 } 3157 3158 /*@ 3159 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3160 3161 Not Collective 3162 3163 Input Parameters: 3164 + dm - The `DMPLEX` 3165 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3166 - size - The cone size for point `p` 3167 3168 Level: beginner 3169 3170 Note: 3171 This should be called after `DMPlexSetChart()`. 3172 3173 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3174 @*/ 3175 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3176 { 3177 DM_Plex *mesh = (DM_Plex *)dm->data; 3178 3179 PetscFunctionBegin; 3180 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3181 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3182 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3183 PetscFunctionReturn(PETSC_SUCCESS); 3184 } 3185 3186 /*@C 3187 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3188 3189 Not Collective 3190 3191 Input Parameters: 3192 + dm - The `DMPLEX` 3193 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3194 3195 Output Parameter: 3196 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3197 3198 Level: beginner 3199 3200 Fortran Notes: 3201 `cone` must be declared with 3202 .vb 3203 PetscInt, pointer :: cone(:) 3204 .ve 3205 3206 You must call `DMPlexRestoreCone()` after you finish using the array. 3207 `DMPlexRestoreCone()` is not needed/available in C. 3208 3209 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3210 @*/ 3211 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3212 { 3213 DM_Plex *mesh = (DM_Plex *)dm->data; 3214 PetscInt off; 3215 3216 PetscFunctionBegin; 3217 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3218 PetscAssertPointer(cone, 3); 3219 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3220 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3221 PetscFunctionReturn(PETSC_SUCCESS); 3222 } 3223 3224 /*@ 3225 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3226 3227 Not Collective 3228 3229 Input Parameters: 3230 + dm - The `DMPLEX` 3231 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3232 3233 Output Parameters: 3234 + pConesSection - `PetscSection` describing the layout of `pCones` 3235 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3236 3237 Level: intermediate 3238 3239 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3240 @*/ 3241 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PeOp PetscSection *pConesSection, PeOp IS *pCones) 3242 { 3243 PetscSection cs, newcs; 3244 PetscInt *cones; 3245 PetscInt *newarr = NULL; 3246 PetscInt n; 3247 3248 PetscFunctionBegin; 3249 PetscCall(DMPlexGetCones(dm, &cones)); 3250 PetscCall(DMPlexGetConeSection(dm, &cs)); 3251 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3252 if (pConesSection) *pConesSection = newcs; 3253 if (pCones) { 3254 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3255 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3256 } 3257 PetscFunctionReturn(PETSC_SUCCESS); 3258 } 3259 3260 /*@ 3261 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3262 3263 Not Collective 3264 3265 Input Parameters: 3266 + dm - The `DMPLEX` 3267 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3268 3269 Output Parameter: 3270 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3271 3272 Level: advanced 3273 3274 Notes: 3275 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3276 3277 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3278 3279 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3280 `DMPlexGetDepth()`, `IS` 3281 @*/ 3282 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3283 { 3284 IS *expandedPointsAll; 3285 PetscInt depth; 3286 3287 PetscFunctionBegin; 3288 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3289 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3290 PetscAssertPointer(expandedPoints, 3); 3291 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3292 *expandedPoints = expandedPointsAll[0]; 3293 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3294 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3295 PetscFunctionReturn(PETSC_SUCCESS); 3296 } 3297 3298 /*@ 3299 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3300 (DAG points of depth 0, i.e., without cones). 3301 3302 Not Collective 3303 3304 Input Parameters: 3305 + dm - The `DMPLEX` 3306 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3307 3308 Output Parameters: 3309 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3310 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3311 - sections - (optional) An array of sections which describe mappings from points to their cone points 3312 3313 Level: advanced 3314 3315 Notes: 3316 Like `DMPlexGetConeTuple()` but recursive. 3317 3318 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. 3319 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3320 3321 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\: 3322 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3323 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3324 3325 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3326 `DMPlexGetDepth()`, `PetscSection`, `IS` 3327 @*/ 3328 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3329 { 3330 const PetscInt *arr0 = NULL, *cone = NULL; 3331 PetscInt *arr = NULL, *newarr = NULL; 3332 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3333 IS *expandedPoints_; 3334 PetscSection *sections_; 3335 3336 PetscFunctionBegin; 3337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3338 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3339 if (depth) PetscAssertPointer(depth, 3); 3340 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3341 if (sections) PetscAssertPointer(sections, 5); 3342 PetscCall(ISGetLocalSize(points, &n)); 3343 PetscCall(ISGetIndices(points, &arr0)); 3344 PetscCall(DMPlexGetDepth(dm, &depth_)); 3345 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3346 PetscCall(PetscCalloc1(depth_, §ions_)); 3347 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3348 for (d = depth_ - 1; d >= 0; d--) { 3349 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3350 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3351 for (i = 0; i < n; i++) { 3352 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3353 if (arr[i] >= start && arr[i] < end) { 3354 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3355 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3356 } else { 3357 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3358 } 3359 } 3360 PetscCall(PetscSectionSetUp(sections_[d])); 3361 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3362 PetscCall(PetscMalloc1(newn, &newarr)); 3363 for (i = 0; i < n; i++) { 3364 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3365 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3366 if (cn > 1) { 3367 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3368 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3369 } else { 3370 newarr[co] = arr[i]; 3371 } 3372 } 3373 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3374 arr = newarr; 3375 n = newn; 3376 } 3377 PetscCall(ISRestoreIndices(points, &arr0)); 3378 *depth = depth_; 3379 if (expandedPoints) *expandedPoints = expandedPoints_; 3380 else { 3381 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3382 PetscCall(PetscFree(expandedPoints_)); 3383 } 3384 if (sections) *sections = sections_; 3385 else { 3386 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3387 PetscCall(PetscFree(sections_)); 3388 } 3389 PetscFunctionReturn(PETSC_SUCCESS); 3390 } 3391 3392 /*@ 3393 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3394 3395 Not Collective 3396 3397 Input Parameters: 3398 + dm - The `DMPLEX` 3399 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3400 3401 Output Parameters: 3402 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3403 . expandedPoints - (optional) An array of recursively expanded cones 3404 - sections - (optional) An array of sections which describe mappings from points to their cone points 3405 3406 Level: advanced 3407 3408 Note: 3409 See `DMPlexGetConeRecursive()` 3410 3411 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3412 `DMPlexGetDepth()`, `IS`, `PetscSection` 3413 @*/ 3414 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3415 { 3416 PetscInt d, depth_; 3417 3418 PetscFunctionBegin; 3419 PetscCall(DMPlexGetDepth(dm, &depth_)); 3420 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3421 if (depth) *depth = 0; 3422 if (expandedPoints) { 3423 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3424 PetscCall(PetscFree(*expandedPoints)); 3425 } 3426 if (sections) { 3427 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3428 PetscCall(PetscFree(*sections)); 3429 } 3430 PetscFunctionReturn(PETSC_SUCCESS); 3431 } 3432 3433 /*@ 3434 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 3435 3436 Not Collective 3437 3438 Input Parameters: 3439 + dm - The `DMPLEX` 3440 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3441 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3442 3443 Level: beginner 3444 3445 Note: 3446 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3447 3448 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3449 @*/ 3450 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3451 { 3452 DM_Plex *mesh = (DM_Plex *)dm->data; 3453 PetscInt dof, off, c; 3454 3455 PetscFunctionBegin; 3456 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3457 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3458 if (dof) PetscAssertPointer(cone, 3); 3459 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3460 if (PetscDefined(USE_DEBUG)) { 3461 PetscInt pStart, pEnd; 3462 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3463 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); 3464 for (c = 0; c < dof; ++c) { 3465 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); 3466 mesh->cones[off + c] = cone[c]; 3467 } 3468 } else { 3469 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3470 } 3471 PetscFunctionReturn(PETSC_SUCCESS); 3472 } 3473 3474 /*@C 3475 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3476 3477 Not Collective 3478 3479 Input Parameters: 3480 + dm - The `DMPLEX` 3481 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3482 3483 Output Parameter: 3484 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3485 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3486 3487 Level: beginner 3488 3489 Note: 3490 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3491 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3492 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3493 with the identity. 3494 3495 Fortran Notes: 3496 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3497 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3498 3499 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3500 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3501 @*/ 3502 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3503 { 3504 DM_Plex *mesh = (DM_Plex *)dm->data; 3505 PetscInt off; 3506 3507 PetscFunctionBegin; 3508 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3509 if (PetscDefined(USE_DEBUG)) { 3510 PetscInt dof; 3511 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3512 if (dof) PetscAssertPointer(coneOrientation, 3); 3513 } 3514 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3515 3516 *coneOrientation = &mesh->coneOrientations[off]; 3517 PetscFunctionReturn(PETSC_SUCCESS); 3518 } 3519 3520 /*@ 3521 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3522 3523 Not Collective 3524 3525 Input Parameters: 3526 + dm - The `DMPLEX` 3527 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3528 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3529 3530 Level: beginner 3531 3532 Notes: 3533 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3534 3535 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3536 3537 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3538 @*/ 3539 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3540 { 3541 DM_Plex *mesh = (DM_Plex *)dm->data; 3542 PetscInt pStart, pEnd; 3543 PetscInt dof, off, c; 3544 3545 PetscFunctionBegin; 3546 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3547 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3548 if (dof) PetscAssertPointer(coneOrientation, 3); 3549 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3550 if (PetscDefined(USE_DEBUG)) { 3551 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3552 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); 3553 for (c = 0; c < dof; ++c) { 3554 PetscInt cdof, o = coneOrientation[c]; 3555 3556 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3557 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); 3558 mesh->coneOrientations[off + c] = o; 3559 } 3560 } else { 3561 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3562 } 3563 PetscFunctionReturn(PETSC_SUCCESS); 3564 } 3565 3566 /*@ 3567 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3568 3569 Not Collective 3570 3571 Input Parameters: 3572 + dm - The `DMPLEX` 3573 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3574 . conePos - The local index in the cone where the point should be put 3575 - conePoint - The mesh point to insert 3576 3577 Level: beginner 3578 3579 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3580 @*/ 3581 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3582 { 3583 DM_Plex *mesh = (DM_Plex *)dm->data; 3584 PetscInt pStart, pEnd; 3585 PetscInt dof, off; 3586 3587 PetscFunctionBegin; 3588 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3589 if (PetscDefined(USE_DEBUG)) { 3590 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3591 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); 3592 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); 3593 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3594 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); 3595 } 3596 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3597 mesh->cones[off + conePos] = conePoint; 3598 PetscFunctionReturn(PETSC_SUCCESS); 3599 } 3600 3601 /*@ 3602 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3603 3604 Not Collective 3605 3606 Input Parameters: 3607 + dm - The `DMPLEX` 3608 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3609 . conePos - The local index in the cone where the point should be put 3610 - coneOrientation - The point orientation to insert 3611 3612 Level: beginner 3613 3614 Note: 3615 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3616 3617 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3618 @*/ 3619 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3620 { 3621 DM_Plex *mesh = (DM_Plex *)dm->data; 3622 PetscInt pStart, pEnd; 3623 PetscInt dof, off; 3624 3625 PetscFunctionBegin; 3626 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3627 if (PetscDefined(USE_DEBUG)) { 3628 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3629 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); 3630 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3631 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); 3632 } 3633 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3634 mesh->coneOrientations[off + conePos] = coneOrientation; 3635 PetscFunctionReturn(PETSC_SUCCESS); 3636 } 3637 3638 /*@C 3639 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3640 3641 Not collective 3642 3643 Input Parameters: 3644 + dm - The DMPlex 3645 - p - The point, which must lie in the chart set with DMPlexSetChart() 3646 3647 Output Parameters: 3648 + cone - An array of points which are on the in-edges for point `p` 3649 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3650 integer giving the prescription for cone traversal. 3651 3652 Level: beginner 3653 3654 Notes: 3655 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3656 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3657 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3658 with the identity. 3659 3660 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3661 3662 Fortran Notes: 3663 `cone` and `ornt` must be declared with 3664 .vb 3665 PetscInt, pointer :: cone(:) 3666 PetscInt, pointer :: ornt(:) 3667 .ve 3668 3669 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3670 @*/ 3671 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, PeOp const PetscInt *cone[], PeOp const PetscInt *ornt[]) 3672 { 3673 DM_Plex *mesh = (DM_Plex *)dm->data; 3674 3675 PetscFunctionBegin; 3676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3677 if (mesh->tr) { 3678 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3679 } else { 3680 PetscInt off; 3681 if (PetscDefined(USE_DEBUG)) { 3682 PetscInt dof; 3683 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3684 if (dof) { 3685 if (cone) PetscAssertPointer(cone, 3); 3686 if (ornt) PetscAssertPointer(ornt, 4); 3687 } 3688 } 3689 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3690 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3691 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3692 } 3693 PetscFunctionReturn(PETSC_SUCCESS); 3694 } 3695 3696 /*@C 3697 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3698 3699 Not Collective 3700 3701 Input Parameters: 3702 + dm - The DMPlex 3703 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3704 . cone - An array of points which are on the in-edges for point p 3705 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3706 integer giving the prescription for cone traversal. 3707 3708 Level: beginner 3709 3710 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3711 @*/ 3712 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3713 { 3714 DM_Plex *mesh = (DM_Plex *)dm->data; 3715 3716 PetscFunctionBegin; 3717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3718 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3719 PetscFunctionReturn(PETSC_SUCCESS); 3720 } 3721 3722 /*@ 3723 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3724 3725 Not Collective 3726 3727 Input Parameters: 3728 + dm - The `DMPLEX` 3729 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3730 3731 Output Parameter: 3732 . size - The support size for point `p` 3733 3734 Level: beginner 3735 3736 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3737 @*/ 3738 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3739 { 3740 DM_Plex *mesh = (DM_Plex *)dm->data; 3741 3742 PetscFunctionBegin; 3743 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3744 PetscAssertPointer(size, 3); 3745 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3746 PetscFunctionReturn(PETSC_SUCCESS); 3747 } 3748 3749 /*@ 3750 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3751 3752 Not Collective 3753 3754 Input Parameters: 3755 + dm - The `DMPLEX` 3756 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3757 - size - The support size for point `p` 3758 3759 Level: beginner 3760 3761 Note: 3762 This should be called after `DMPlexSetChart()`. 3763 3764 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3765 @*/ 3766 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3767 { 3768 DM_Plex *mesh = (DM_Plex *)dm->data; 3769 3770 PetscFunctionBegin; 3771 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3772 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3773 PetscFunctionReturn(PETSC_SUCCESS); 3774 } 3775 3776 /*@C 3777 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3778 3779 Not Collective 3780 3781 Input Parameters: 3782 + dm - The `DMPLEX` 3783 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3784 3785 Output Parameter: 3786 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3787 3788 Level: beginner 3789 3790 Fortran Notes: 3791 `support` must be declared with 3792 .vb 3793 PetscInt, pointer :: support(:) 3794 .ve 3795 3796 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3797 `DMPlexRestoreSupport()` is not needed/available in C. 3798 3799 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3800 @*/ 3801 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3802 { 3803 DM_Plex *mesh = (DM_Plex *)dm->data; 3804 PetscInt off; 3805 3806 PetscFunctionBegin; 3807 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3808 PetscAssertPointer(support, 3); 3809 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3810 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3811 PetscFunctionReturn(PETSC_SUCCESS); 3812 } 3813 3814 /*@ 3815 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3816 3817 Not Collective 3818 3819 Input Parameters: 3820 + dm - The `DMPLEX` 3821 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3822 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3823 3824 Level: beginner 3825 3826 Note: 3827 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3828 3829 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3830 @*/ 3831 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3832 { 3833 DM_Plex *mesh = (DM_Plex *)dm->data; 3834 PetscInt pStart, pEnd; 3835 PetscInt dof, off, c; 3836 3837 PetscFunctionBegin; 3838 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3839 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3840 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3841 if (dof) PetscAssertPointer(support, 3); 3842 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3843 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); 3844 for (c = 0; c < dof; ++c) { 3845 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); 3846 mesh->supports[off + c] = support[c]; 3847 } 3848 PetscFunctionReturn(PETSC_SUCCESS); 3849 } 3850 3851 /*@ 3852 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3853 3854 Not Collective 3855 3856 Input Parameters: 3857 + dm - The `DMPLEX` 3858 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3859 . supportPos - The local index in the cone where the point should be put 3860 - supportPoint - The mesh point to insert 3861 3862 Level: beginner 3863 3864 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3865 @*/ 3866 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3867 { 3868 DM_Plex *mesh = (DM_Plex *)dm->data; 3869 PetscInt pStart, pEnd; 3870 PetscInt dof, off; 3871 3872 PetscFunctionBegin; 3873 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3874 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3875 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3876 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3877 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); 3878 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); 3879 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); 3880 mesh->supports[off + supportPos] = supportPoint; 3881 PetscFunctionReturn(PETSC_SUCCESS); 3882 } 3883 3884 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3885 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3886 { 3887 switch (ct) { 3888 case DM_POLYTOPE_SEGMENT: 3889 if (o == -1) return -2; 3890 break; 3891 case DM_POLYTOPE_TRIANGLE: 3892 if (o == -3) return -1; 3893 if (o == -2) return -3; 3894 if (o == -1) return -2; 3895 break; 3896 case DM_POLYTOPE_QUADRILATERAL: 3897 if (o == -4) return -2; 3898 if (o == -3) return -1; 3899 if (o == -2) return -4; 3900 if (o == -1) return -3; 3901 break; 3902 default: 3903 return o; 3904 } 3905 return o; 3906 } 3907 3908 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3909 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3910 { 3911 switch (ct) { 3912 case DM_POLYTOPE_SEGMENT: 3913 if ((o == -2) || (o == 1)) return -1; 3914 if (o == -1) return 0; 3915 break; 3916 case DM_POLYTOPE_TRIANGLE: 3917 if (o == -3) return -2; 3918 if (o == -2) return -1; 3919 if (o == -1) return -3; 3920 break; 3921 case DM_POLYTOPE_QUADRILATERAL: 3922 if (o == -4) return -2; 3923 if (o == -3) return -1; 3924 if (o == -2) return -4; 3925 if (o == -1) return -3; 3926 break; 3927 default: 3928 return o; 3929 } 3930 return o; 3931 } 3932 3933 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3934 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3935 { 3936 PetscInt pStart, pEnd, p; 3937 3938 PetscFunctionBegin; 3939 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3940 for (p = pStart; p < pEnd; ++p) { 3941 const PetscInt *cone, *ornt; 3942 PetscInt coneSize, c; 3943 3944 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3945 PetscCall(DMPlexGetCone(dm, p, &cone)); 3946 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3947 for (c = 0; c < coneSize; ++c) { 3948 DMPolytopeType ct; 3949 const PetscInt o = ornt[c]; 3950 3951 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3952 switch (ct) { 3953 case DM_POLYTOPE_SEGMENT: 3954 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3955 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3956 break; 3957 case DM_POLYTOPE_TRIANGLE: 3958 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3959 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3960 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3961 break; 3962 case DM_POLYTOPE_QUADRILATERAL: 3963 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3964 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3965 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3966 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3967 break; 3968 default: 3969 break; 3970 } 3971 } 3972 } 3973 PetscFunctionReturn(PETSC_SUCCESS); 3974 } 3975 3976 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3977 { 3978 DM_Plex *mesh = (DM_Plex *)dm->data; 3979 3980 PetscFunctionBeginHot; 3981 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3982 if (useCone) { 3983 PetscCall(DMPlexGetConeSize(dm, p, size)); 3984 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3985 } else { 3986 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3987 PetscCall(DMPlexGetSupport(dm, p, arr)); 3988 } 3989 } else { 3990 if (useCone) { 3991 const PetscSection s = mesh->coneSection; 3992 const PetscInt ps = p - s->pStart; 3993 const PetscInt off = s->atlasOff[ps]; 3994 3995 *size = s->atlasDof[ps]; 3996 *arr = mesh->cones + off; 3997 *ornt = mesh->coneOrientations + off; 3998 } else { 3999 const PetscSection s = mesh->supportSection; 4000 const PetscInt ps = p - s->pStart; 4001 const PetscInt off = s->atlasOff[ps]; 4002 4003 *size = s->atlasDof[ps]; 4004 *arr = mesh->supports + off; 4005 } 4006 } 4007 PetscFunctionReturn(PETSC_SUCCESS); 4008 } 4009 4010 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 4011 { 4012 DM_Plex *mesh = (DM_Plex *)dm->data; 4013 4014 PetscFunctionBeginHot; 4015 if (PetscDefined(USE_DEBUG) || mesh->tr) { 4016 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 4017 } 4018 PetscFunctionReturn(PETSC_SUCCESS); 4019 } 4020 4021 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4022 { 4023 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4024 PetscInt *closure; 4025 const PetscInt *tmp = NULL, *tmpO = NULL; 4026 PetscInt off = 0, tmpSize, t; 4027 4028 PetscFunctionBeginHot; 4029 if (ornt) { 4030 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4031 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; 4032 } 4033 if (*points) { 4034 closure = *points; 4035 } else { 4036 PetscInt maxConeSize, maxSupportSize; 4037 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4038 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 4039 } 4040 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4041 if (ct == DM_POLYTOPE_UNKNOWN) { 4042 closure[off++] = p; 4043 closure[off++] = 0; 4044 for (t = 0; t < tmpSize; ++t) { 4045 closure[off++] = tmp[t]; 4046 closure[off++] = tmpO ? tmpO[t] : 0; 4047 } 4048 } else { 4049 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 4050 4051 /* We assume that cells with a valid type have faces with a valid type */ 4052 closure[off++] = p; 4053 closure[off++] = ornt; 4054 for (t = 0; t < tmpSize; ++t) { 4055 DMPolytopeType ft; 4056 4057 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 4058 closure[off++] = tmp[arr[t]]; 4059 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 4060 } 4061 } 4062 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4063 if (numPoints) *numPoints = tmpSize + 1; 4064 if (points) *points = closure; 4065 PetscFunctionReturn(PETSC_SUCCESS); 4066 } 4067 4068 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 4069 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 4070 { 4071 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 4072 const PetscInt *cone, *ornt; 4073 PetscInt *pts, *closure = NULL; 4074 DMPolytopeType ft; 4075 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 4076 PetscInt dim, coneSize, c, d, clSize, cl; 4077 4078 PetscFunctionBeginHot; 4079 PetscCall(DMGetDimension(dm, &dim)); 4080 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4081 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4082 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4083 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4084 maxSize = PetscMax(coneSeries, supportSeries); 4085 if (*points) { 4086 pts = *points; 4087 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4088 c = 0; 4089 pts[c++] = point; 4090 pts[c++] = o; 4091 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4092 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4093 for (cl = 0; cl < clSize * 2; cl += 2) { 4094 pts[c++] = closure[cl]; 4095 pts[c++] = closure[cl + 1]; 4096 } 4097 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4098 for (cl = 0; cl < clSize * 2; cl += 2) { 4099 pts[c++] = closure[cl]; 4100 pts[c++] = closure[cl + 1]; 4101 } 4102 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4103 for (d = 2; d < coneSize; ++d) { 4104 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4105 pts[c++] = cone[arr[d * 2 + 0]]; 4106 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4107 } 4108 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4109 if (dim >= 3) { 4110 for (d = 2; d < coneSize; ++d) { 4111 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4112 const PetscInt *fcone, *fornt; 4113 PetscInt fconeSize, fc, i; 4114 4115 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4116 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4117 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4118 for (fc = 0; fc < fconeSize; ++fc) { 4119 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4120 const PetscInt co = farr[fc * 2 + 1]; 4121 4122 for (i = 0; i < c; i += 2) 4123 if (pts[i] == cp) break; 4124 if (i == c) { 4125 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4126 pts[c++] = cp; 4127 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4128 } 4129 } 4130 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4131 } 4132 } 4133 *numPoints = c / 2; 4134 *points = pts; 4135 PetscFunctionReturn(PETSC_SUCCESS); 4136 } 4137 4138 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4139 { 4140 DMPolytopeType ct; 4141 PetscInt *closure, *fifo; 4142 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4143 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4144 PetscInt depth, maxSize; 4145 4146 PetscFunctionBeginHot; 4147 PetscCall(DMPlexGetDepth(dm, &depth)); 4148 if (depth == 1) { 4149 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4150 PetscFunctionReturn(PETSC_SUCCESS); 4151 } 4152 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4153 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; 4154 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4155 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4156 PetscFunctionReturn(PETSC_SUCCESS); 4157 } 4158 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4159 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4160 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4161 maxSize = PetscMax(coneSeries, supportSeries); 4162 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4163 if (*points) { 4164 closure = *points; 4165 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4166 closure[closureSize++] = p; 4167 closure[closureSize++] = ornt; 4168 fifo[fifoSize++] = p; 4169 fifo[fifoSize++] = ornt; 4170 fifo[fifoSize++] = ct; 4171 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4172 while (fifoSize - fifoStart) { 4173 const PetscInt q = fifo[fifoStart++]; 4174 const PetscInt o = fifo[fifoStart++]; 4175 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4176 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4177 const PetscInt *tmp, *tmpO = NULL; 4178 PetscInt tmpSize, t; 4179 4180 if (PetscDefined(USE_DEBUG)) { 4181 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4182 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); 4183 } 4184 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4185 for (t = 0; t < tmpSize; ++t) { 4186 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4187 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4188 const PetscInt cp = tmp[ip]; 4189 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4190 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4191 PetscInt c; 4192 4193 /* Check for duplicate */ 4194 for (c = 0; c < closureSize; c += 2) { 4195 if (closure[c] == cp) break; 4196 } 4197 if (c == closureSize) { 4198 closure[closureSize++] = cp; 4199 closure[closureSize++] = co; 4200 fifo[fifoSize++] = cp; 4201 fifo[fifoSize++] = co; 4202 fifo[fifoSize++] = ct; 4203 } 4204 } 4205 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4206 } 4207 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4208 if (numPoints) *numPoints = closureSize / 2; 4209 if (points) *points = closure; 4210 PetscFunctionReturn(PETSC_SUCCESS); 4211 } 4212 4213 /*@C 4214 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4215 4216 Not Collective 4217 4218 Input Parameters: 4219 + dm - The `DMPLEX` 4220 . p - The mesh point 4221 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4222 4223 Input/Output Parameter: 4224 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4225 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4226 otherwise the provided array is used to hold the values 4227 4228 Output Parameter: 4229 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4230 4231 Level: beginner 4232 4233 Note: 4234 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4235 4236 Fortran Notes: 4237 `points` must be declared with 4238 .vb 4239 PetscInt, pointer :: points(:) 4240 .ve 4241 and is always allocated by the function. 4242 4243 Pass `PETSC_NULL_INTEGER` for `numPoints` if it is not needed 4244 4245 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4246 @*/ 4247 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4248 { 4249 PetscFunctionBeginHot; 4250 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4251 if (numPoints) PetscAssertPointer(numPoints, 4); 4252 if (points) PetscAssertPointer(points, 5); 4253 if (PetscDefined(USE_DEBUG)) { 4254 PetscInt pStart, pEnd; 4255 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4256 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); 4257 } 4258 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4259 PetscFunctionReturn(PETSC_SUCCESS); 4260 } 4261 4262 /*@C 4263 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4264 4265 Not Collective 4266 4267 Input Parameters: 4268 + dm - The `DMPLEX` 4269 . p - The mesh point 4270 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4271 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4272 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4273 4274 Level: beginner 4275 4276 Note: 4277 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4278 4279 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4280 @*/ 4281 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4282 { 4283 PetscFunctionBeginHot; 4284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4285 if (numPoints) *numPoints = 0; 4286 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4287 PetscFunctionReturn(PETSC_SUCCESS); 4288 } 4289 4290 /*@ 4291 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4292 4293 Not Collective 4294 4295 Input Parameter: 4296 . dm - The `DMPLEX` 4297 4298 Output Parameters: 4299 + maxConeSize - The maximum number of in-edges 4300 - maxSupportSize - The maximum number of out-edges 4301 4302 Level: beginner 4303 4304 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4305 @*/ 4306 PetscErrorCode DMPlexGetMaxSizes(DM dm, PeOp PetscInt *maxConeSize, PeOp PetscInt *maxSupportSize) 4307 { 4308 DM_Plex *mesh = (DM_Plex *)dm->data; 4309 4310 PetscFunctionBegin; 4311 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4312 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4313 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4314 PetscFunctionReturn(PETSC_SUCCESS); 4315 } 4316 4317 PetscErrorCode DMSetUp_Plex(DM dm) 4318 { 4319 DM_Plex *mesh = (DM_Plex *)dm->data; 4320 PetscInt size, maxSupportSize; 4321 4322 PetscFunctionBegin; 4323 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4324 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4325 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4326 PetscCall(PetscMalloc1(size, &mesh->cones)); 4327 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4328 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4329 if (maxSupportSize) { 4330 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4331 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4332 PetscCall(PetscMalloc1(size, &mesh->supports)); 4333 } 4334 PetscFunctionReturn(PETSC_SUCCESS); 4335 } 4336 4337 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4338 { 4339 PetscFunctionBegin; 4340 if (subdm) PetscCall(DMClone(dm, subdm)); 4341 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4342 if (subdm) (*subdm)->useNatural = dm->useNatural; 4343 if (dm->useNatural && dm->sfMigration) { 4344 PetscSF sfNatural; 4345 4346 (*subdm)->sfMigration = dm->sfMigration; 4347 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4348 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4349 (*subdm)->sfNatural = sfNatural; 4350 } 4351 PetscFunctionReturn(PETSC_SUCCESS); 4352 } 4353 4354 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4355 { 4356 PetscInt i = 0; 4357 4358 PetscFunctionBegin; 4359 PetscCall(DMClone(dms[0], superdm)); 4360 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4361 (*superdm)->useNatural = PETSC_FALSE; 4362 for (i = 0; i < len; i++) { 4363 if (dms[i]->useNatural && dms[i]->sfMigration) { 4364 PetscSF sfNatural; 4365 4366 (*superdm)->sfMigration = dms[i]->sfMigration; 4367 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4368 (*superdm)->useNatural = PETSC_TRUE; 4369 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4370 (*superdm)->sfNatural = sfNatural; 4371 break; 4372 } 4373 } 4374 PetscFunctionReturn(PETSC_SUCCESS); 4375 } 4376 4377 /*@ 4378 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4379 4380 Not Collective 4381 4382 Input Parameter: 4383 . dm - The `DMPLEX` 4384 4385 Level: beginner 4386 4387 Note: 4388 This should be called after all calls to `DMPlexSetCone()` 4389 4390 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4391 @*/ 4392 PetscErrorCode DMPlexSymmetrize(DM dm) 4393 { 4394 DM_Plex *mesh = (DM_Plex *)dm->data; 4395 PetscInt *offsets; 4396 PetscInt supportSize; 4397 PetscInt pStart, pEnd, p; 4398 4399 PetscFunctionBegin; 4400 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4401 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4402 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4403 /* Calculate support sizes */ 4404 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4405 for (p = pStart; p < pEnd; ++p) { 4406 PetscInt dof, off, c; 4407 4408 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4409 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4410 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4411 } 4412 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4413 /* Calculate supports */ 4414 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4415 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4416 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4417 for (p = pStart; p < pEnd; ++p) { 4418 PetscInt dof, off, c; 4419 4420 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4421 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4422 for (c = off; c < off + dof; ++c) { 4423 const PetscInt q = mesh->cones[c]; 4424 PetscInt offS; 4425 4426 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4427 4428 mesh->supports[offS + offsets[q]] = p; 4429 ++offsets[q]; 4430 } 4431 } 4432 PetscCall(PetscFree(offsets)); 4433 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4434 PetscFunctionReturn(PETSC_SUCCESS); 4435 } 4436 4437 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4438 { 4439 IS stratumIS; 4440 4441 PetscFunctionBegin; 4442 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4443 if (PetscDefined(USE_DEBUG)) { 4444 PetscInt qStart, qEnd, numLevels, level; 4445 PetscBool overlap = PETSC_FALSE; 4446 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4447 for (level = 0; level < numLevels; level++) { 4448 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4449 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4450 overlap = PETSC_TRUE; 4451 break; 4452 } 4453 } 4454 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); 4455 } 4456 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4457 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4458 PetscCall(ISDestroy(&stratumIS)); 4459 PetscFunctionReturn(PETSC_SUCCESS); 4460 } 4461 4462 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4463 { 4464 PetscInt *pMin, *pMax; 4465 PetscInt pStart, pEnd; 4466 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4467 4468 PetscFunctionBegin; 4469 { 4470 DMLabel label2; 4471 4472 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4473 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4474 } 4475 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4476 for (PetscInt p = pStart; p < pEnd; ++p) { 4477 DMPolytopeType ct; 4478 4479 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4480 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4481 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4482 } 4483 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4484 for (PetscInt d = dmin; d <= dmax; ++d) { 4485 pMin[d] = PETSC_INT_MAX; 4486 pMax[d] = PETSC_INT_MIN; 4487 } 4488 for (PetscInt p = pStart; p < pEnd; ++p) { 4489 DMPolytopeType ct; 4490 PetscInt d; 4491 4492 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4493 d = DMPolytopeTypeGetDim(ct); 4494 pMin[d] = PetscMin(p, pMin[d]); 4495 pMax[d] = PetscMax(p, pMax[d]); 4496 } 4497 for (PetscInt d = dmin; d <= dmax; ++d) { 4498 if (pMin[d] > pMax[d]) continue; 4499 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4500 } 4501 PetscCall(PetscFree2(pMin, pMax)); 4502 PetscFunctionReturn(PETSC_SUCCESS); 4503 } 4504 4505 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4506 { 4507 PetscInt pStart, pEnd; 4508 PetscInt numRoots = 0, numLeaves = 0; 4509 4510 PetscFunctionBegin; 4511 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4512 { 4513 /* Initialize roots and count leaves */ 4514 PetscInt sMin = PETSC_INT_MAX; 4515 PetscInt sMax = PETSC_INT_MIN; 4516 PetscInt coneSize, supportSize; 4517 4518 for (PetscInt p = pStart; p < pEnd; ++p) { 4519 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4520 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4521 if (!coneSize && supportSize) { 4522 sMin = PetscMin(p, sMin); 4523 sMax = PetscMax(p, sMax); 4524 ++numRoots; 4525 } else if (!supportSize && coneSize) { 4526 ++numLeaves; 4527 } else if (!supportSize && !coneSize) { 4528 /* Isolated points */ 4529 sMin = PetscMin(p, sMin); 4530 sMax = PetscMax(p, sMax); 4531 } 4532 } 4533 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4534 } 4535 4536 if (numRoots + numLeaves == (pEnd - pStart)) { 4537 PetscInt sMin = PETSC_INT_MAX; 4538 PetscInt sMax = PETSC_INT_MIN; 4539 PetscInt coneSize, supportSize; 4540 4541 for (PetscInt p = pStart; p < pEnd; ++p) { 4542 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4543 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4544 if (!supportSize && coneSize) { 4545 sMin = PetscMin(p, sMin); 4546 sMax = PetscMax(p, sMax); 4547 } 4548 } 4549 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4550 } else { 4551 PetscInt level = 0; 4552 PetscInt qStart, qEnd; 4553 4554 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4555 while (qEnd > qStart) { 4556 PetscInt sMin = PETSC_INT_MAX; 4557 PetscInt sMax = PETSC_INT_MIN; 4558 4559 for (PetscInt q = qStart; q < qEnd; ++q) { 4560 const PetscInt *support; 4561 PetscInt supportSize; 4562 4563 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4564 PetscCall(DMPlexGetSupport(dm, q, &support)); 4565 for (PetscInt s = 0; s < supportSize; ++s) { 4566 sMin = PetscMin(support[s], sMin); 4567 sMax = PetscMax(support[s], sMax); 4568 } 4569 } 4570 PetscCall(DMLabelGetNumValues(label, &level)); 4571 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4572 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4573 } 4574 } 4575 PetscFunctionReturn(PETSC_SUCCESS); 4576 } 4577 4578 /*@ 4579 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4580 4581 Collective 4582 4583 Input Parameter: 4584 . dm - The `DMPLEX` 4585 4586 Level: beginner 4587 4588 Notes: 4589 The strata group all points of the same grade, and this function calculates the strata. This 4590 grade can be seen as the height (or depth) of the point in the DAG. 4591 4592 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4593 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4594 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4595 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4596 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4597 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4598 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4599 4600 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4601 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4602 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 4603 to interpolate only that one (e0), so that 4604 .vb 4605 cone(c0) = {e0, v2} 4606 cone(e0) = {v0, v1} 4607 .ve 4608 If `DMPlexStratify()` is run on this mesh, it will give depths 4609 .vb 4610 depth 0 = {v0, v1, v2} 4611 depth 1 = {e0, c0} 4612 .ve 4613 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4614 4615 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4616 4617 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4618 @*/ 4619 PetscErrorCode DMPlexStratify(DM dm) 4620 { 4621 DM_Plex *mesh = (DM_Plex *)dm->data; 4622 DMLabel label; 4623 PetscBool flg = PETSC_FALSE; 4624 4625 PetscFunctionBegin; 4626 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4627 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4628 4629 // Create depth label 4630 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4631 PetscCall(DMCreateLabel(dm, "depth")); 4632 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4633 4634 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4635 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4636 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4637 4638 { /* just in case there is an empty process */ 4639 PetscInt numValues, maxValues = 0, v; 4640 4641 PetscCall(DMLabelGetNumValues(label, &numValues)); 4642 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4643 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4644 } 4645 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4646 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4647 PetscFunctionReturn(PETSC_SUCCESS); 4648 } 4649 4650 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4651 { 4652 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4653 PetscInt dim, depth, pheight, coneSize; 4654 PetscBool preferTensor; 4655 4656 PetscFunctionBeginHot; 4657 PetscCall(DMGetDimension(dm, &dim)); 4658 PetscCall(DMPlexGetDepth(dm, &depth)); 4659 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4660 PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor)); 4661 pheight = depth - pdepth; 4662 if (depth <= 1) { 4663 switch (pdepth) { 4664 case 0: 4665 ct = DM_POLYTOPE_POINT; 4666 break; 4667 case 1: 4668 switch (coneSize) { 4669 case 2: 4670 ct = DM_POLYTOPE_SEGMENT; 4671 break; 4672 case 3: 4673 ct = DM_POLYTOPE_TRIANGLE; 4674 break; 4675 case 4: 4676 switch (dim) { 4677 case 2: 4678 ct = DM_POLYTOPE_QUADRILATERAL; 4679 break; 4680 case 3: 4681 ct = DM_POLYTOPE_TETRAHEDRON; 4682 break; 4683 default: 4684 break; 4685 } 4686 break; 4687 case 5: 4688 ct = DM_POLYTOPE_PYRAMID; 4689 break; 4690 case 6: 4691 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4692 break; 4693 case 8: 4694 ct = DM_POLYTOPE_HEXAHEDRON; 4695 break; 4696 default: 4697 break; 4698 } 4699 } 4700 } else { 4701 if (pdepth == 0) { 4702 ct = DM_POLYTOPE_POINT; 4703 } else if (pheight == 0) { 4704 switch (dim) { 4705 case 1: 4706 switch (coneSize) { 4707 case 2: 4708 ct = DM_POLYTOPE_SEGMENT; 4709 break; 4710 default: 4711 break; 4712 } 4713 break; 4714 case 2: 4715 switch (coneSize) { 4716 case 3: 4717 ct = DM_POLYTOPE_TRIANGLE; 4718 break; 4719 case 4: 4720 ct = DM_POLYTOPE_QUADRILATERAL; 4721 break; 4722 default: 4723 break; 4724 } 4725 break; 4726 case 3: 4727 switch (coneSize) { 4728 case 4: 4729 ct = DM_POLYTOPE_TETRAHEDRON; 4730 break; 4731 case 5: { 4732 const PetscInt *cone; 4733 PetscInt faceConeSize; 4734 4735 PetscCall(DMPlexGetCone(dm, p, &cone)); 4736 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4737 switch (faceConeSize) { 4738 case 3: 4739 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4740 break; 4741 case 4: 4742 ct = DM_POLYTOPE_PYRAMID; 4743 break; 4744 } 4745 } break; 4746 case 6: 4747 ct = DM_POLYTOPE_HEXAHEDRON; 4748 break; 4749 default: 4750 break; 4751 } 4752 break; 4753 default: 4754 break; 4755 } 4756 } else if (pheight > 0) { 4757 switch (coneSize) { 4758 case 2: 4759 ct = DM_POLYTOPE_SEGMENT; 4760 break; 4761 case 3: 4762 ct = DM_POLYTOPE_TRIANGLE; 4763 break; 4764 case 4: 4765 ct = DM_POLYTOPE_QUADRILATERAL; 4766 break; 4767 default: 4768 break; 4769 } 4770 } 4771 } 4772 *pt = ct; 4773 PetscFunctionReturn(PETSC_SUCCESS); 4774 } 4775 4776 /*@ 4777 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4778 4779 Collective 4780 4781 Input Parameter: 4782 . dm - The `DMPLEX` 4783 4784 Level: developer 4785 4786 Note: 4787 This function is normally called automatically when a cell type is requested. It creates an 4788 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4789 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4790 4791 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4792 4793 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4794 @*/ 4795 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4796 { 4797 DM_Plex *mesh; 4798 DMLabel ctLabel; 4799 PetscInt pStart, pEnd, p; 4800 4801 PetscFunctionBegin; 4802 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4803 mesh = (DM_Plex *)dm->data; 4804 PetscCall(DMCreateLabel(dm, "celltype")); 4805 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4806 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4807 PetscCall(PetscFree(mesh->cellTypes)); 4808 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4809 for (p = pStart; p < pEnd; ++p) { 4810 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4811 PetscInt pdepth; 4812 4813 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4814 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4815 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]); 4816 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4817 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4818 } 4819 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4820 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4821 PetscFunctionReturn(PETSC_SUCCESS); 4822 } 4823 4824 /*@C 4825 DMPlexGetJoin - Get an array for the join of the set of points 4826 4827 Not Collective 4828 4829 Input Parameters: 4830 + dm - The `DMPLEX` object 4831 . numPoints - The number of input points for the join 4832 - points - The input points 4833 4834 Output Parameters: 4835 + numCoveredPoints - The number of points in the join 4836 - coveredPoints - The points in the join 4837 4838 Level: intermediate 4839 4840 Note: 4841 Currently, this is restricted to a single level join 4842 4843 Fortran Notes: 4844 `converedPoints` must be declared with 4845 .vb 4846 PetscInt, pointer :: coveredPints(:) 4847 .ve 4848 4849 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4850 @*/ 4851 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4852 { 4853 DM_Plex *mesh = (DM_Plex *)dm->data; 4854 PetscInt *join[2]; 4855 PetscInt joinSize, i = 0; 4856 PetscInt dof, off, p, c, m; 4857 PetscInt maxSupportSize; 4858 4859 PetscFunctionBegin; 4860 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4861 PetscAssertPointer(points, 3); 4862 PetscAssertPointer(numCoveredPoints, 4); 4863 PetscAssertPointer(coveredPoints, 5); 4864 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4865 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4866 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4867 /* Copy in support of first point */ 4868 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4869 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4870 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4871 /* Check each successive support */ 4872 for (p = 1; p < numPoints; ++p) { 4873 PetscInt newJoinSize = 0; 4874 4875 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4876 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4877 for (c = 0; c < dof; ++c) { 4878 const PetscInt point = mesh->supports[off + c]; 4879 4880 for (m = 0; m < joinSize; ++m) { 4881 if (point == join[i][m]) { 4882 join[1 - i][newJoinSize++] = point; 4883 break; 4884 } 4885 } 4886 } 4887 joinSize = newJoinSize; 4888 i = 1 - i; 4889 } 4890 *numCoveredPoints = joinSize; 4891 *coveredPoints = join[i]; 4892 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4893 PetscFunctionReturn(PETSC_SUCCESS); 4894 } 4895 4896 /*@C 4897 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4898 4899 Not Collective 4900 4901 Input Parameters: 4902 + dm - The `DMPLEX` object 4903 . numPoints - The number of input points for the join 4904 - points - The input points 4905 4906 Output Parameters: 4907 + numCoveredPoints - The number of points in the join 4908 - coveredPoints - The points in the join 4909 4910 Level: intermediate 4911 4912 Fortran Notes: 4913 `converedPoints` must be declared with 4914 .vb 4915 PetscInt, pointer :: coveredPoints(:) 4916 .ve 4917 4918 Pass `PETSC_NULL_INTEGER` for `numCoveredPoints` if it is not needed 4919 4920 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4921 @*/ 4922 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4923 { 4924 PetscFunctionBegin; 4925 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4926 if (points) PetscAssertPointer(points, 3); 4927 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4928 PetscAssertPointer(coveredPoints, 5); 4929 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4930 if (numCoveredPoints) *numCoveredPoints = 0; 4931 PetscFunctionReturn(PETSC_SUCCESS); 4932 } 4933 4934 /*@C 4935 DMPlexGetFullJoin - Get an array for the join of the set of points 4936 4937 Not Collective 4938 4939 Input Parameters: 4940 + dm - The `DMPLEX` object 4941 . numPoints - The number of input points for the join 4942 - points - The input points, its length is `numPoints` 4943 4944 Output Parameters: 4945 + numCoveredPoints - The number of points in the join 4946 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4947 4948 Level: intermediate 4949 4950 Fortran Notes: 4951 .vb 4952 PetscInt, pointer :: coveredPints(:) 4953 .ve 4954 4955 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4956 @*/ 4957 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4958 { 4959 PetscInt *offsets, **closures; 4960 PetscInt *join[2]; 4961 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4962 PetscInt p, d, c, m, ms; 4963 4964 PetscFunctionBegin; 4965 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4966 PetscAssertPointer(points, 3); 4967 PetscAssertPointer(numCoveredPoints, 4); 4968 PetscAssertPointer(coveredPoints, 5); 4969 4970 PetscCall(DMPlexGetDepth(dm, &depth)); 4971 PetscCall(PetscCalloc1(numPoints, &closures)); 4972 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4973 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4974 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4975 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4976 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4977 4978 for (p = 0; p < numPoints; ++p) { 4979 PetscInt closureSize; 4980 4981 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4982 4983 offsets[p * (depth + 2) + 0] = 0; 4984 for (d = 0; d < depth + 1; ++d) { 4985 PetscInt pStart, pEnd, i; 4986 4987 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4988 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4989 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4990 offsets[p * (depth + 2) + d + 1] = i; 4991 break; 4992 } 4993 } 4994 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4995 } 4996 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); 4997 } 4998 for (d = 0; d < depth + 1; ++d) { 4999 PetscInt dof; 5000 5001 /* Copy in support of first point */ 5002 dof = offsets[d + 1] - offsets[d]; 5003 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 5004 /* Check each successive cone */ 5005 for (p = 1; p < numPoints && joinSize; ++p) { 5006 PetscInt newJoinSize = 0; 5007 5008 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 5009 for (c = 0; c < dof; ++c) { 5010 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 5011 5012 for (m = 0; m < joinSize; ++m) { 5013 if (point == join[i][m]) { 5014 join[1 - i][newJoinSize++] = point; 5015 break; 5016 } 5017 } 5018 } 5019 joinSize = newJoinSize; 5020 i = 1 - i; 5021 } 5022 if (joinSize) break; 5023 } 5024 *numCoveredPoints = joinSize; 5025 *coveredPoints = join[i]; 5026 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 5027 PetscCall(PetscFree(closures)); 5028 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 5029 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 5030 PetscFunctionReturn(PETSC_SUCCESS); 5031 } 5032 5033 /*@C 5034 DMPlexGetMeet - Get an array for the meet of the set of points 5035 5036 Not Collective 5037 5038 Input Parameters: 5039 + dm - The `DMPLEX` object 5040 . numPoints - The number of input points for the meet 5041 - points - The input points, of length `numPoints` 5042 5043 Output Parameters: 5044 + numCoveringPoints - The number of points in the meet 5045 - coveringPoints - The points in the meet, of length `numCoveringPoints` 5046 5047 Level: intermediate 5048 5049 Note: 5050 Currently, this is restricted to a single level meet 5051 5052 Fortran Note: 5053 `coveringPoints` must be declared with 5054 .vb 5055 PetscInt, pointer :: coveringPoints(:) 5056 .ve 5057 5058 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5059 @*/ 5060 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 5061 { 5062 DM_Plex *mesh = (DM_Plex *)dm->data; 5063 PetscInt *meet[2]; 5064 PetscInt meetSize, i = 0; 5065 PetscInt dof, off, p, c, m; 5066 PetscInt maxConeSize; 5067 5068 PetscFunctionBegin; 5069 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5070 PetscAssertPointer(points, 3); 5071 PetscAssertPointer(numCoveringPoints, 4); 5072 PetscAssertPointer(coveringPoints, 5); 5073 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 5074 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 5075 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 5076 /* Copy in cone of first point */ 5077 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 5078 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 5079 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5080 /* Check each successive cone */ 5081 for (p = 1; p < numPoints; ++p) { 5082 PetscInt newMeetSize = 0; 5083 5084 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5085 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5086 for (c = 0; c < dof; ++c) { 5087 const PetscInt point = mesh->cones[off + c]; 5088 5089 for (m = 0; m < meetSize; ++m) { 5090 if (point == meet[i][m]) { 5091 meet[1 - i][newMeetSize++] = point; 5092 break; 5093 } 5094 } 5095 } 5096 meetSize = newMeetSize; 5097 i = 1 - i; 5098 } 5099 *numCoveringPoints = meetSize; 5100 *coveringPoints = meet[i]; 5101 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5102 PetscFunctionReturn(PETSC_SUCCESS); 5103 } 5104 5105 /*@C 5106 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5107 5108 Not Collective 5109 5110 Input Parameters: 5111 + dm - The `DMPLEX` object 5112 . numPoints - The number of input points for the meet 5113 - points - The input points 5114 5115 Output Parameters: 5116 + numCoveredPoints - The number of points in the meet 5117 - coveredPoints - The points in the meet 5118 5119 Level: intermediate 5120 5121 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5122 @*/ 5123 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5124 { 5125 PetscFunctionBegin; 5126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5127 if (points) PetscAssertPointer(points, 3); 5128 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5129 PetscAssertPointer(coveredPoints, 5); 5130 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5131 if (numCoveredPoints) *numCoveredPoints = 0; 5132 PetscFunctionReturn(PETSC_SUCCESS); 5133 } 5134 5135 /*@C 5136 DMPlexGetFullMeet - Get an array for the meet of the set of points 5137 5138 Not Collective 5139 5140 Input Parameters: 5141 + dm - The `DMPLEX` object 5142 . numPoints - The number of input points for the meet 5143 - points - The input points, of length `numPoints` 5144 5145 Output Parameters: 5146 + numCoveredPoints - The number of points in the meet 5147 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5148 5149 Level: intermediate 5150 5151 Fortran Notes: 5152 `coveredPoints` must be declared with 5153 .vb 5154 PetscInt, pointer :: coveredPoints(:) 5155 .ve 5156 5157 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5158 @*/ 5159 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5160 { 5161 PetscInt *offsets, **closures; 5162 PetscInt *meet[2]; 5163 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5164 PetscInt p, h, c, m, mc; 5165 5166 PetscFunctionBegin; 5167 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5168 PetscAssertPointer(points, 3); 5169 PetscAssertPointer(numCoveredPoints, 4); 5170 PetscAssertPointer(coveredPoints, 5); 5171 5172 PetscCall(DMPlexGetDepth(dm, &height)); 5173 PetscCall(PetscMalloc1(numPoints, &closures)); 5174 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5175 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5176 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5177 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5178 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5179 5180 for (p = 0; p < numPoints; ++p) { 5181 PetscInt closureSize; 5182 5183 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5184 5185 offsets[p * (height + 2) + 0] = 0; 5186 for (h = 0; h < height + 1; ++h) { 5187 PetscInt pStart, pEnd, i; 5188 5189 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5190 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5191 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5192 offsets[p * (height + 2) + h + 1] = i; 5193 break; 5194 } 5195 } 5196 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5197 } 5198 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); 5199 } 5200 for (h = 0; h < height + 1; ++h) { 5201 PetscInt dof; 5202 5203 /* Copy in cone of first point */ 5204 dof = offsets[h + 1] - offsets[h]; 5205 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5206 /* Check each successive cone */ 5207 for (p = 1; p < numPoints && meetSize; ++p) { 5208 PetscInt newMeetSize = 0; 5209 5210 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5211 for (c = 0; c < dof; ++c) { 5212 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5213 5214 for (m = 0; m < meetSize; ++m) { 5215 if (point == meet[i][m]) { 5216 meet[1 - i][newMeetSize++] = point; 5217 break; 5218 } 5219 } 5220 } 5221 meetSize = newMeetSize; 5222 i = 1 - i; 5223 } 5224 if (meetSize) break; 5225 } 5226 *numCoveredPoints = meetSize; 5227 *coveredPoints = meet[i]; 5228 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5229 PetscCall(PetscFree(closures)); 5230 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5231 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5232 PetscFunctionReturn(PETSC_SUCCESS); 5233 } 5234 5235 /*@ 5236 DMPlexEqual - Determine if two `DM` have the same topology 5237 5238 Not Collective 5239 5240 Input Parameters: 5241 + dmA - A `DMPLEX` object 5242 - dmB - A `DMPLEX` object 5243 5244 Output Parameter: 5245 . equal - `PETSC_TRUE` if the topologies are identical 5246 5247 Level: intermediate 5248 5249 Note: 5250 We are not solving graph isomorphism, so we do not permute. 5251 5252 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5253 @*/ 5254 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5255 { 5256 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5257 5258 PetscFunctionBegin; 5259 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5260 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5261 PetscAssertPointer(equal, 3); 5262 5263 *equal = PETSC_FALSE; 5264 PetscCall(DMPlexGetDepth(dmA, &depth)); 5265 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5266 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5267 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5268 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5269 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5270 for (p = pStart; p < pEnd; ++p) { 5271 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5272 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5273 5274 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5275 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5276 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5277 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5278 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5279 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5280 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5281 for (c = 0; c < coneSize; ++c) { 5282 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5283 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5284 } 5285 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5286 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5287 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5288 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5289 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5290 for (s = 0; s < supportSize; ++s) { 5291 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5292 } 5293 } 5294 *equal = PETSC_TRUE; 5295 PetscFunctionReturn(PETSC_SUCCESS); 5296 } 5297 5298 /*@ 5299 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5300 5301 Not Collective 5302 5303 Input Parameters: 5304 + dm - The `DMPLEX` 5305 . cellDim - The cell dimension 5306 - numCorners - The number of vertices on a cell 5307 5308 Output Parameter: 5309 . numFaceVertices - The number of vertices on a face 5310 5311 Level: developer 5312 5313 Note: 5314 Of course this can only work for a restricted set of symmetric shapes 5315 5316 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5317 @*/ 5318 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5319 { 5320 MPI_Comm comm; 5321 5322 PetscFunctionBegin; 5323 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5324 PetscAssertPointer(numFaceVertices, 4); 5325 switch (cellDim) { 5326 case 0: 5327 *numFaceVertices = 0; 5328 break; 5329 case 1: 5330 *numFaceVertices = 1; 5331 break; 5332 case 2: 5333 switch (numCorners) { 5334 case 3: /* triangle */ 5335 *numFaceVertices = 2; /* Edge has 2 vertices */ 5336 break; 5337 case 4: /* quadrilateral */ 5338 *numFaceVertices = 2; /* Edge has 2 vertices */ 5339 break; 5340 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5341 *numFaceVertices = 3; /* Edge has 3 vertices */ 5342 break; 5343 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5344 *numFaceVertices = 3; /* Edge has 3 vertices */ 5345 break; 5346 default: 5347 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5348 } 5349 break; 5350 case 3: 5351 switch (numCorners) { 5352 case 4: /* tetradehdron */ 5353 *numFaceVertices = 3; /* Face has 3 vertices */ 5354 break; 5355 case 6: /* tet cohesive cells */ 5356 *numFaceVertices = 4; /* Face has 4 vertices */ 5357 break; 5358 case 8: /* hexahedron */ 5359 *numFaceVertices = 4; /* Face has 4 vertices */ 5360 break; 5361 case 9: /* tet cohesive Lagrange cells */ 5362 *numFaceVertices = 6; /* Face has 6 vertices */ 5363 break; 5364 case 10: /* quadratic tetrahedron */ 5365 *numFaceVertices = 6; /* Face has 6 vertices */ 5366 break; 5367 case 12: /* hex cohesive Lagrange cells */ 5368 *numFaceVertices = 6; /* Face has 6 vertices */ 5369 break; 5370 case 18: /* quadratic tet cohesive Lagrange cells */ 5371 *numFaceVertices = 6; /* Face has 6 vertices */ 5372 break; 5373 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5374 *numFaceVertices = 9; /* Face has 9 vertices */ 5375 break; 5376 default: 5377 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5378 } 5379 break; 5380 default: 5381 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5382 } 5383 PetscFunctionReturn(PETSC_SUCCESS); 5384 } 5385 5386 /*@ 5387 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5388 5389 Not Collective 5390 5391 Input Parameter: 5392 . dm - The `DMPLEX` object 5393 5394 Output Parameter: 5395 . depthLabel - The `DMLabel` recording point depth 5396 5397 Level: developer 5398 5399 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5400 @*/ 5401 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5402 { 5403 PetscFunctionBegin; 5404 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5405 PetscAssertPointer(depthLabel, 2); 5406 *depthLabel = dm->depthLabel; 5407 PetscFunctionReturn(PETSC_SUCCESS); 5408 } 5409 5410 /*@ 5411 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5412 5413 Not Collective 5414 5415 Input Parameter: 5416 . dm - The `DMPLEX` object 5417 5418 Output Parameter: 5419 . depth - The number of strata (breadth first levels) in the DAG 5420 5421 Level: developer 5422 5423 Notes: 5424 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5425 5426 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5427 5428 An empty mesh gives -1. 5429 5430 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5431 @*/ 5432 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5433 { 5434 DM_Plex *mesh = (DM_Plex *)dm->data; 5435 DMLabel label; 5436 PetscInt d = -1; 5437 5438 PetscFunctionBegin; 5439 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5440 PetscAssertPointer(depth, 2); 5441 if (mesh->tr) { 5442 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5443 } else { 5444 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5445 // Allow missing depths 5446 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5447 *depth = d; 5448 } 5449 PetscFunctionReturn(PETSC_SUCCESS); 5450 } 5451 5452 /*@ 5453 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5454 5455 Not Collective 5456 5457 Input Parameters: 5458 + dm - The `DMPLEX` object 5459 - depth - The requested depth 5460 5461 Output Parameters: 5462 + start - The first point at this `depth` 5463 - end - One beyond the last point at this `depth` 5464 5465 Level: developer 5466 5467 Notes: 5468 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5469 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5470 higher dimension, e.g., "edges". 5471 5472 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5473 @*/ 5474 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PeOp PetscInt *start, PeOp PetscInt *end) 5475 { 5476 DM_Plex *mesh = (DM_Plex *)dm->data; 5477 DMLabel label; 5478 PetscInt pStart, pEnd; 5479 5480 PetscFunctionBegin; 5481 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5482 if (start) { 5483 PetscAssertPointer(start, 3); 5484 *start = 0; 5485 } 5486 if (end) { 5487 PetscAssertPointer(end, 4); 5488 *end = 0; 5489 } 5490 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5491 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5492 if (depth < 0) { 5493 if (start) *start = pStart; 5494 if (end) *end = pEnd; 5495 PetscFunctionReturn(PETSC_SUCCESS); 5496 } 5497 if (mesh->tr) { 5498 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5499 } else { 5500 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5501 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5502 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5503 } 5504 PetscFunctionReturn(PETSC_SUCCESS); 5505 } 5506 5507 /*@ 5508 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5509 5510 Not Collective 5511 5512 Input Parameters: 5513 + dm - The `DMPLEX` object 5514 - height - The requested height 5515 5516 Output Parameters: 5517 + start - The first point at this `height` 5518 - end - One beyond the last point at this `height` 5519 5520 Level: developer 5521 5522 Notes: 5523 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5524 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5525 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5526 5527 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5528 @*/ 5529 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PeOp PetscInt *start, PeOp PetscInt *end) 5530 { 5531 DMLabel label; 5532 PetscInt depth, pStart, pEnd; 5533 5534 PetscFunctionBegin; 5535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5536 if (start) { 5537 PetscAssertPointer(start, 3); 5538 *start = 0; 5539 } 5540 if (end) { 5541 PetscAssertPointer(end, 4); 5542 *end = 0; 5543 } 5544 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5545 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5546 if (height < 0) { 5547 if (start) *start = pStart; 5548 if (end) *end = pEnd; 5549 PetscFunctionReturn(PETSC_SUCCESS); 5550 } 5551 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5552 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5553 else PetscCall(DMGetDimension(dm, &depth)); 5554 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5555 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5556 PetscFunctionReturn(PETSC_SUCCESS); 5557 } 5558 5559 /*@ 5560 DMPlexGetPointDepth - Get the `depth` of a given point 5561 5562 Not Collective 5563 5564 Input Parameters: 5565 + dm - The `DMPLEX` object 5566 - point - The point 5567 5568 Output Parameter: 5569 . depth - The depth of the `point` 5570 5571 Level: intermediate 5572 5573 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5574 @*/ 5575 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5576 { 5577 PetscFunctionBegin; 5578 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5579 PetscAssertPointer(depth, 3); 5580 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5581 PetscFunctionReturn(PETSC_SUCCESS); 5582 } 5583 5584 /*@ 5585 DMPlexGetPointHeight - Get the `height` of a given point 5586 5587 Not Collective 5588 5589 Input Parameters: 5590 + dm - The `DMPLEX` object 5591 - point - The point 5592 5593 Output Parameter: 5594 . height - The height of the `point` 5595 5596 Level: intermediate 5597 5598 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5599 @*/ 5600 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5601 { 5602 PetscInt n, pDepth; 5603 5604 PetscFunctionBegin; 5605 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5606 PetscAssertPointer(height, 3); 5607 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5608 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5609 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5610 PetscFunctionReturn(PETSC_SUCCESS); 5611 } 5612 5613 /*@ 5614 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5615 5616 Not Collective 5617 5618 Input Parameter: 5619 . dm - The `DMPLEX` object 5620 5621 Output Parameter: 5622 . celltypeLabel - The `DMLabel` recording cell polytope type 5623 5624 Level: developer 5625 5626 Note: 5627 This function will trigger automatica computation of cell types. This can be disabled by calling 5628 `DMCreateLabel`(dm, "celltype") beforehand. 5629 5630 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5631 @*/ 5632 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5633 { 5634 PetscFunctionBegin; 5635 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5636 PetscAssertPointer(celltypeLabel, 2); 5637 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5638 *celltypeLabel = dm->celltypeLabel; 5639 PetscFunctionReturn(PETSC_SUCCESS); 5640 } 5641 5642 /*@ 5643 DMPlexGetCellType - Get the polytope type of a given cell 5644 5645 Not Collective 5646 5647 Input Parameters: 5648 + dm - The `DMPLEX` object 5649 - cell - The cell 5650 5651 Output Parameter: 5652 . celltype - The polytope type of the cell 5653 5654 Level: intermediate 5655 5656 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5657 @*/ 5658 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5659 { 5660 DM_Plex *mesh = (DM_Plex *)dm->data; 5661 DMLabel label; 5662 PetscInt ct; 5663 5664 PetscFunctionBegin; 5665 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5666 PetscAssertPointer(celltype, 3); 5667 if (mesh->tr) { 5668 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5669 } else { 5670 PetscInt pStart, pEnd; 5671 5672 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5673 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5674 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5675 if (pEnd <= pStart) { 5676 *celltype = DM_POLYTOPE_UNKNOWN; 5677 PetscFunctionReturn(PETSC_SUCCESS); 5678 } 5679 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5680 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5681 for (PetscInt p = pStart; p < pEnd; p++) { 5682 PetscCall(DMLabelGetValue(label, p, &ct)); 5683 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5684 } 5685 } 5686 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5687 if (PetscDefined(USE_DEBUG)) { 5688 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5689 PetscCall(DMLabelGetValue(label, cell, &ct)); 5690 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5691 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5692 } 5693 } 5694 PetscFunctionReturn(PETSC_SUCCESS); 5695 } 5696 5697 /*@ 5698 DMPlexSetCellType - Set the polytope type of a given cell 5699 5700 Not Collective 5701 5702 Input Parameters: 5703 + dm - The `DMPLEX` object 5704 . cell - The cell 5705 - celltype - The polytope type of the cell 5706 5707 Level: advanced 5708 5709 Note: 5710 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5711 is executed. This function will override the computed type. However, if automatic classification will not succeed 5712 and a user wants to manually specify all types, the classification must be disabled by calling 5713 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5714 5715 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5716 @*/ 5717 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5718 { 5719 DM_Plex *mesh = (DM_Plex *)dm->data; 5720 DMLabel label; 5721 PetscInt pStart, pEnd; 5722 5723 PetscFunctionBegin; 5724 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5725 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5726 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5727 PetscCall(DMLabelSetValue(label, cell, celltype)); 5728 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5729 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5730 PetscFunctionReturn(PETSC_SUCCESS); 5731 } 5732 5733 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5734 { 5735 PetscSection section; 5736 PetscInt maxHeight; 5737 const char *prefix; 5738 5739 PetscFunctionBegin; 5740 PetscCall(DMClone(dm, cdm)); 5741 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5742 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5743 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5744 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5745 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5746 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5747 PetscCall(DMSetLocalSection(*cdm, section)); 5748 PetscCall(PetscSectionDestroy(§ion)); 5749 5750 PetscCall(DMSetNumFields(*cdm, 1)); 5751 PetscCall(DMCreateDS(*cdm)); 5752 (*cdm)->cloneOpts = PETSC_TRUE; 5753 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5754 PetscFunctionReturn(PETSC_SUCCESS); 5755 } 5756 5757 PetscErrorCode DMCreateCellCoordinateDM_Plex(DM dm, DM *cdm) 5758 { 5759 DM cgcdm; 5760 PetscSection section; 5761 const char *prefix; 5762 5763 PetscFunctionBegin; 5764 PetscCall(DMGetCoordinateDM(dm, &cgcdm)); 5765 PetscCall(DMClone(cgcdm, cdm)); 5766 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5767 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5768 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cellcdm_")); 5769 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5770 PetscCall(DMSetLocalSection(*cdm, section)); 5771 PetscCall(PetscSectionDestroy(§ion)); 5772 PetscCall(DMSetNumFields(*cdm, 1)); 5773 PetscCall(DMCreateDS(*cdm)); 5774 (*cdm)->cloneOpts = PETSC_TRUE; 5775 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5776 PetscFunctionReturn(PETSC_SUCCESS); 5777 } 5778 5779 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5780 { 5781 Vec coordsLocal, cellCoordsLocal; 5782 DM coordsDM, cellCoordsDM; 5783 5784 PetscFunctionBegin; 5785 *field = NULL; 5786 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5787 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5788 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5789 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5790 if (coordsLocal && coordsDM) { 5791 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5792 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5793 } 5794 PetscFunctionReturn(PETSC_SUCCESS); 5795 } 5796 5797 /*@ 5798 DMPlexGetConeSection - Return a section which describes the layout of cone data 5799 5800 Not Collective 5801 5802 Input Parameter: 5803 . dm - The `DMPLEX` object 5804 5805 Output Parameter: 5806 . section - The `PetscSection` object 5807 5808 Level: developer 5809 5810 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5811 @*/ 5812 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5813 { 5814 DM_Plex *mesh = (DM_Plex *)dm->data; 5815 5816 PetscFunctionBegin; 5817 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5818 if (section) *section = mesh->coneSection; 5819 PetscFunctionReturn(PETSC_SUCCESS); 5820 } 5821 5822 /*@ 5823 DMPlexGetSupportSection - Return a section which describes the layout of support data 5824 5825 Not Collective 5826 5827 Input Parameter: 5828 . dm - The `DMPLEX` object 5829 5830 Output Parameter: 5831 . section - The `PetscSection` object 5832 5833 Level: developer 5834 5835 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5836 @*/ 5837 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5838 { 5839 DM_Plex *mesh = (DM_Plex *)dm->data; 5840 5841 PetscFunctionBegin; 5842 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5843 if (section) *section = mesh->supportSection; 5844 PetscFunctionReturn(PETSC_SUCCESS); 5845 } 5846 5847 /*@C 5848 DMPlexGetCones - Return cone data 5849 5850 Not Collective 5851 5852 Input Parameter: 5853 . dm - The `DMPLEX` object 5854 5855 Output Parameter: 5856 . cones - The cone for each point 5857 5858 Level: developer 5859 5860 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5861 @*/ 5862 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5863 { 5864 DM_Plex *mesh = (DM_Plex *)dm->data; 5865 5866 PetscFunctionBegin; 5867 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5868 if (cones) *cones = mesh->cones; 5869 PetscFunctionReturn(PETSC_SUCCESS); 5870 } 5871 5872 /*@C 5873 DMPlexGetConeOrientations - Return cone orientation data 5874 5875 Not Collective 5876 5877 Input Parameter: 5878 . dm - The `DMPLEX` object 5879 5880 Output Parameter: 5881 . coneOrientations - The array of cone orientations for all points 5882 5883 Level: developer 5884 5885 Notes: 5886 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5887 as returned by `DMPlexGetConeOrientation()`. 5888 5889 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5890 5891 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5892 @*/ 5893 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5894 { 5895 DM_Plex *mesh = (DM_Plex *)dm->data; 5896 5897 PetscFunctionBegin; 5898 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5899 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5900 PetscFunctionReturn(PETSC_SUCCESS); 5901 } 5902 5903 /* FEM Support */ 5904 5905 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5906 { 5907 PetscInt depth; 5908 5909 PetscFunctionBegin; 5910 PetscCall(DMPlexGetDepth(plex, &depth)); 5911 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5912 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5913 PetscFunctionReturn(PETSC_SUCCESS); 5914 } 5915 5916 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5917 { 5918 PetscInt depth; 5919 5920 PetscFunctionBegin; 5921 PetscCall(DMPlexGetDepth(plex, &depth)); 5922 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5923 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5924 PetscFunctionReturn(PETSC_SUCCESS); 5925 } 5926 5927 /* 5928 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5929 representing a line in the section. 5930 */ 5931 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5932 { 5933 PetscObject obj; 5934 PetscClassId id; 5935 PetscFE fe = NULL; 5936 5937 PetscFunctionBeginHot; 5938 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5939 PetscCall(DMGetField(dm, field, NULL, &obj)); 5940 PetscCall(PetscObjectGetClassId(obj, &id)); 5941 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5942 5943 if (!fe) { 5944 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5945 /* An order k SEM disc has k-1 dofs on an edge */ 5946 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5947 *k = *k / *Nc + 1; 5948 } else { 5949 PetscInt dual_space_size, dim; 5950 PetscDualSpace dsp; 5951 5952 PetscCall(DMGetDimension(dm, &dim)); 5953 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5954 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5955 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5956 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5957 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5958 } 5959 PetscFunctionReturn(PETSC_SUCCESS); 5960 } 5961 5962 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5963 { 5964 PetscFunctionBeginHot; 5965 if (tensor) { 5966 *dof = PetscPowInt(k + 1, dim); 5967 } else { 5968 switch (dim) { 5969 case 1: 5970 *dof = k + 1; 5971 break; 5972 case 2: 5973 *dof = ((k + 1) * (k + 2)) / 2; 5974 break; 5975 case 3: 5976 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5977 break; 5978 default: 5979 *dof = 0; 5980 } 5981 } 5982 PetscFunctionReturn(PETSC_SUCCESS); 5983 } 5984 5985 /*@ 5986 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5987 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5988 section provided (or the section of the `DM`). 5989 5990 Input Parameters: 5991 + dm - The `DM` 5992 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5993 - section - The `PetscSection` to reorder, or `NULL` for the default section 5994 5995 Example: 5996 A typical interpolated single-quad mesh might order points as 5997 .vb 5998 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5999 6000 v4 -- e6 -- v3 6001 | | 6002 e7 c0 e8 6003 | | 6004 v1 -- e5 -- v2 6005 .ve 6006 6007 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 6008 dofs in the order of points, e.g., 6009 .vb 6010 c0 -> [0,1,2,3] 6011 v1 -> [4] 6012 ... 6013 e5 -> [8, 9] 6014 .ve 6015 6016 which corresponds to the dofs 6017 .vb 6018 6 10 11 7 6019 13 2 3 15 6020 12 0 1 14 6021 4 8 9 5 6022 .ve 6023 6024 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 6025 .vb 6026 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 6027 .ve 6028 6029 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 6030 .vb 6031 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 6032 .ve 6033 6034 Level: developer 6035 6036 Notes: 6037 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 6038 degree of the basis. 6039 6040 This is required to run with libCEED. 6041 6042 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 6043 @*/ 6044 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 6045 { 6046 DMLabel label; 6047 PetscInt dim, depth = -1, eStart = -1, Nf; 6048 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 6049 6050 PetscFunctionBegin; 6051 PetscCall(DMGetDimension(dm, &dim)); 6052 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 6053 if (point < 0) { 6054 PetscInt sStart, sEnd; 6055 6056 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6057 point = sEnd - sStart ? sStart : point; 6058 } 6059 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6060 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6061 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6062 if (depth == 1) { 6063 eStart = point; 6064 } else if (depth == dim) { 6065 const PetscInt *cone; 6066 6067 PetscCall(DMPlexGetCone(dm, point, &cone)); 6068 if (dim == 2) eStart = cone[0]; 6069 else if (dim == 3) { 6070 const PetscInt *cone2; 6071 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6072 eStart = cone2[0]; 6073 } 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); 6074 } 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); 6075 6076 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6077 for (PetscInt d = 1; d <= dim; d++) { 6078 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6079 PetscInt *perm; 6080 6081 for (f = 0; f < Nf; ++f) { 6082 PetscInt dof; 6083 6084 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6085 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6086 if (!continuous && d < dim) continue; 6087 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6088 size += dof * Nc; 6089 } 6090 PetscCall(PetscMalloc1(size, &perm)); 6091 for (f = 0; f < Nf; ++f) { 6092 switch (d) { 6093 case 1: 6094 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6095 if (!continuous && d < dim) continue; 6096 /* 6097 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6098 We want [ vtx0; edge of length k-1; vtx1 ] 6099 */ 6100 if (continuous) { 6101 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6102 for (i = 0; i < k - 1; i++) 6103 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6104 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6105 foffset = offset; 6106 } else { 6107 PetscInt dof; 6108 6109 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6110 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6111 foffset = offset; 6112 } 6113 break; 6114 case 2: 6115 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6116 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6117 if (!continuous && d < dim) continue; 6118 /* The SEM order is 6119 6120 v_lb, {e_b}, v_rb, 6121 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6122 v_lt, reverse {e_t}, v_rt 6123 */ 6124 if (continuous) { 6125 const PetscInt of = 0; 6126 const PetscInt oeb = of + PetscSqr(k - 1); 6127 const PetscInt oer = oeb + (k - 1); 6128 const PetscInt oet = oer + (k - 1); 6129 const PetscInt oel = oet + (k - 1); 6130 const PetscInt ovlb = oel + (k - 1); 6131 const PetscInt ovrb = ovlb + 1; 6132 const PetscInt ovrt = ovrb + 1; 6133 const PetscInt ovlt = ovrt + 1; 6134 PetscInt o; 6135 6136 /* bottom */ 6137 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6138 for (o = oeb; o < oer; ++o) 6139 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6140 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6141 /* middle */ 6142 for (i = 0; i < k - 1; ++i) { 6143 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6144 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6145 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6146 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6147 } 6148 /* top */ 6149 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6150 for (o = oel - 1; o >= oet; --o) 6151 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6152 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6153 foffset = offset; 6154 } else { 6155 PetscInt dof; 6156 6157 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6158 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6159 foffset = offset; 6160 } 6161 break; 6162 case 3: 6163 /* The original hex closure is 6164 6165 {c, 6166 f_b, f_t, f_f, f_b, f_r, f_l, 6167 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6168 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6169 */ 6170 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6171 if (!continuous && d < dim) continue; 6172 /* The SEM order is 6173 Bottom Slice 6174 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6175 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6176 v_blb, {e_bb}, v_brb, 6177 6178 Middle Slice (j) 6179 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6180 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6181 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6182 6183 Top Slice 6184 v_tlf, {e_tf}, v_trf, 6185 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6186 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6187 */ 6188 if (continuous) { 6189 const PetscInt oc = 0; 6190 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6191 const PetscInt oft = ofb + PetscSqr(k - 1); 6192 const PetscInt off = oft + PetscSqr(k - 1); 6193 const PetscInt ofk = off + PetscSqr(k - 1); 6194 const PetscInt ofr = ofk + PetscSqr(k - 1); 6195 const PetscInt ofl = ofr + PetscSqr(k - 1); 6196 const PetscInt oebl = ofl + PetscSqr(k - 1); 6197 const PetscInt oebb = oebl + (k - 1); 6198 const PetscInt oebr = oebb + (k - 1); 6199 const PetscInt oebf = oebr + (k - 1); 6200 const PetscInt oetf = oebf + (k - 1); 6201 const PetscInt oetr = oetf + (k - 1); 6202 const PetscInt oetb = oetr + (k - 1); 6203 const PetscInt oetl = oetb + (k - 1); 6204 const PetscInt oerf = oetl + (k - 1); 6205 const PetscInt oelf = oerf + (k - 1); 6206 const PetscInt oelb = oelf + (k - 1); 6207 const PetscInt oerb = oelb + (k - 1); 6208 const PetscInt ovblf = oerb + (k - 1); 6209 const PetscInt ovblb = ovblf + 1; 6210 const PetscInt ovbrb = ovblb + 1; 6211 const PetscInt ovbrf = ovbrb + 1; 6212 const PetscInt ovtlf = ovbrf + 1; 6213 const PetscInt ovtrf = ovtlf + 1; 6214 const PetscInt ovtrb = ovtrf + 1; 6215 const PetscInt ovtlb = ovtrb + 1; 6216 PetscInt o, n; 6217 6218 /* Bottom Slice */ 6219 /* bottom */ 6220 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6221 for (o = oetf - 1; o >= oebf; --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] = ovbrf * Nc + c + foffset; 6224 /* middle */ 6225 for (i = 0; i < k - 1; ++i) { 6226 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6227 for (n = 0; n < k - 1; ++n) { 6228 o = ofb + n * (k - 1) + i; 6229 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6230 } 6231 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6232 } 6233 /* top */ 6234 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6235 for (o = oebb; o < oebr; ++o) 6236 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6237 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6238 6239 /* Middle Slice */ 6240 for (j = 0; j < k - 1; ++j) { 6241 /* bottom */ 6242 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6243 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6244 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6245 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6246 /* middle */ 6247 for (i = 0; i < k - 1; ++i) { 6248 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6249 for (n = 0; n < k - 1; ++n) 6250 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6251 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6252 } 6253 /* top */ 6254 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6255 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6256 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6257 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6258 } 6259 6260 /* Top Slice */ 6261 /* bottom */ 6262 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6263 for (o = oetf; o < oetr; ++o) 6264 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6265 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6266 /* middle */ 6267 for (i = 0; i < k - 1; ++i) { 6268 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6269 for (n = 0; n < k - 1; ++n) 6270 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6271 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6272 } 6273 /* top */ 6274 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6275 for (o = oetl - 1; o >= oetb; --o) 6276 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6277 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6278 6279 foffset = offset; 6280 } else { 6281 PetscInt dof; 6282 6283 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6284 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6285 foffset = offset; 6286 } 6287 break; 6288 default: 6289 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6290 } 6291 } 6292 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6293 /* Check permutation */ 6294 { 6295 PetscInt *check; 6296 6297 PetscCall(PetscMalloc1(size, &check)); 6298 for (i = 0; i < size; ++i) { 6299 check[i] = -1; 6300 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6301 } 6302 for (i = 0; i < size; ++i) check[perm[i]] = i; 6303 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6304 PetscCall(PetscFree(check)); 6305 } 6306 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6307 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6308 PetscInt *loc_perm; 6309 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6310 for (PetscInt i = 0; i < size; i++) { 6311 loc_perm[i] = perm[i]; 6312 loc_perm[size + i] = size + perm[i]; 6313 } 6314 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6315 } 6316 } 6317 PetscFunctionReturn(PETSC_SUCCESS); 6318 } 6319 6320 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6321 { 6322 PetscDS prob; 6323 PetscInt depth, Nf, h; 6324 DMLabel label; 6325 6326 PetscFunctionBeginHot; 6327 PetscCall(DMGetDS(dm, &prob)); 6328 Nf = prob->Nf; 6329 label = dm->depthLabel; 6330 *dspace = NULL; 6331 if (field < Nf) { 6332 PetscObject disc = prob->disc[field]; 6333 6334 if (disc->classid == PETSCFE_CLASSID) { 6335 PetscDualSpace dsp; 6336 6337 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6338 PetscCall(DMLabelGetNumValues(label, &depth)); 6339 PetscCall(DMLabelGetValue(label, point, &h)); 6340 h = depth - 1 - h; 6341 if (h) { 6342 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6343 } else { 6344 *dspace = dsp; 6345 } 6346 } 6347 } 6348 PetscFunctionReturn(PETSC_SUCCESS); 6349 } 6350 6351 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6352 { 6353 PetscScalar *array; 6354 const PetscScalar *vArray; 6355 const PetscInt *cone, *coneO; 6356 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6357 6358 PetscFunctionBeginHot; 6359 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6360 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6361 PetscCall(DMPlexGetCone(dm, point, &cone)); 6362 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6363 if (!values || !*values) { 6364 if ((point >= pStart) && (point < pEnd)) { 6365 PetscInt dof; 6366 6367 PetscCall(PetscSectionGetDof(section, point, &dof)); 6368 size += dof; 6369 } 6370 for (p = 0; p < numPoints; ++p) { 6371 const PetscInt cp = cone[p]; 6372 PetscInt dof; 6373 6374 if ((cp < pStart) || (cp >= pEnd)) continue; 6375 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6376 size += dof; 6377 } 6378 if (!values) { 6379 if (csize) *csize = size; 6380 PetscFunctionReturn(PETSC_SUCCESS); 6381 } 6382 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6383 } else { 6384 array = *values; 6385 } 6386 size = 0; 6387 PetscCall(VecGetArrayRead(v, &vArray)); 6388 if ((point >= pStart) && (point < pEnd)) { 6389 PetscInt dof, off, d; 6390 const PetscScalar *varr; 6391 6392 PetscCall(PetscSectionGetDof(section, point, &dof)); 6393 PetscCall(PetscSectionGetOffset(section, point, &off)); 6394 varr = PetscSafePointerPlusOffset(vArray, off); 6395 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6396 size += dof; 6397 } 6398 for (p = 0; p < numPoints; ++p) { 6399 const PetscInt cp = cone[p]; 6400 PetscInt o = coneO[p]; 6401 PetscInt dof, off, d; 6402 const PetscScalar *varr; 6403 6404 if ((cp < pStart) || (cp >= pEnd)) continue; 6405 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6406 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6407 varr = PetscSafePointerPlusOffset(vArray, off); 6408 if (o >= 0) { 6409 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6410 } else { 6411 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6412 } 6413 size += dof; 6414 } 6415 PetscCall(VecRestoreArrayRead(v, &vArray)); 6416 if (!*values) { 6417 if (csize) *csize = size; 6418 *values = array; 6419 } else { 6420 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6421 *csize = size; 6422 } 6423 PetscFunctionReturn(PETSC_SUCCESS); 6424 } 6425 6426 /* Compress out points not in the section */ 6427 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6428 { 6429 const PetscInt np = *numPoints; 6430 PetscInt pStart, pEnd, p, q; 6431 6432 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6433 for (p = 0, q = 0; p < np; ++p) { 6434 const PetscInt r = points[p * 2]; 6435 if ((r >= pStart) && (r < pEnd)) { 6436 points[q * 2] = r; 6437 points[q * 2 + 1] = points[p * 2 + 1]; 6438 ++q; 6439 } 6440 } 6441 *numPoints = q; 6442 return PETSC_SUCCESS; 6443 } 6444 6445 /* Compressed closure does not apply closure permutation */ 6446 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6447 { 6448 const PetscInt *cla = NULL; 6449 PetscInt np, *pts = NULL; 6450 6451 PetscFunctionBeginHot; 6452 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6453 if (!ornt && *clPoints) { 6454 PetscInt dof, off; 6455 6456 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6457 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6458 PetscCall(ISGetIndices(*clPoints, &cla)); 6459 np = dof / 2; 6460 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6461 } else { 6462 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6463 PetscCall(CompressPoints_Private(section, &np, pts)); 6464 } 6465 *numPoints = np; 6466 *points = pts; 6467 *clp = cla; 6468 PetscFunctionReturn(PETSC_SUCCESS); 6469 } 6470 6471 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6472 { 6473 PetscFunctionBeginHot; 6474 if (!*clPoints) { 6475 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6476 } else { 6477 PetscCall(ISRestoreIndices(*clPoints, clp)); 6478 } 6479 *numPoints = 0; 6480 *points = NULL; 6481 *clSec = NULL; 6482 *clPoints = NULL; 6483 *clp = NULL; 6484 PetscFunctionReturn(PETSC_SUCCESS); 6485 } 6486 6487 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6488 { 6489 PetscInt offset = 0, p; 6490 const PetscInt **perms = NULL; 6491 const PetscScalar **flips = NULL; 6492 6493 PetscFunctionBeginHot; 6494 *size = 0; 6495 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6496 for (p = 0; p < numPoints; p++) { 6497 const PetscInt point = points[2 * p]; 6498 const PetscInt *perm = perms ? perms[p] : NULL; 6499 const PetscScalar *flip = flips ? flips[p] : NULL; 6500 PetscInt dof, off, d; 6501 const PetscScalar *varr; 6502 6503 PetscCall(PetscSectionGetDof(section, point, &dof)); 6504 PetscCall(PetscSectionGetOffset(section, point, &off)); 6505 varr = PetscSafePointerPlusOffset(vArray, off); 6506 if (clperm) { 6507 if (perm) { 6508 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6509 } else { 6510 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6511 } 6512 if (flip) { 6513 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6514 } 6515 } else { 6516 if (perm) { 6517 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6518 } else { 6519 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6520 } 6521 if (flip) { 6522 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6523 } 6524 } 6525 offset += dof; 6526 } 6527 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6528 *size = offset; 6529 PetscFunctionReturn(PETSC_SUCCESS); 6530 } 6531 6532 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[]) 6533 { 6534 PetscInt offset = 0, f; 6535 6536 PetscFunctionBeginHot; 6537 *size = 0; 6538 for (f = 0; f < numFields; ++f) { 6539 PetscInt p; 6540 const PetscInt **perms = NULL; 6541 const PetscScalar **flips = NULL; 6542 6543 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6544 for (p = 0; p < numPoints; p++) { 6545 const PetscInt point = points[2 * p]; 6546 PetscInt fdof, foff, b; 6547 const PetscScalar *varr; 6548 const PetscInt *perm = perms ? perms[p] : NULL; 6549 const PetscScalar *flip = flips ? flips[p] : NULL; 6550 6551 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6552 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6553 varr = &vArray[foff]; 6554 if (clperm) { 6555 if (perm) { 6556 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6557 } else { 6558 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6559 } 6560 if (flip) { 6561 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6562 } 6563 } else { 6564 if (perm) { 6565 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6566 } else { 6567 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6568 } 6569 if (flip) { 6570 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6571 } 6572 } 6573 offset += fdof; 6574 } 6575 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6576 } 6577 *size = offset; 6578 PetscFunctionReturn(PETSC_SUCCESS); 6579 } 6580 6581 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6582 { 6583 PetscSection clSection; 6584 IS clPoints; 6585 PetscInt *points = NULL; 6586 const PetscInt *clp, *perm = NULL; 6587 PetscInt depth, numFields, numPoints, asize; 6588 6589 PetscFunctionBeginHot; 6590 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6591 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6592 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6593 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6594 PetscCall(DMPlexGetDepth(dm, &depth)); 6595 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6596 if (depth == 1 && numFields < 2) { 6597 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6598 PetscFunctionReturn(PETSC_SUCCESS); 6599 } 6600 /* Get points */ 6601 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6602 /* Get sizes */ 6603 asize = 0; 6604 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6605 PetscInt dof; 6606 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6607 asize += dof; 6608 } 6609 if (values) { 6610 const PetscScalar *vArray; 6611 PetscInt size; 6612 6613 if (*values) { 6614 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); 6615 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6616 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6617 PetscCall(VecGetArrayRead(v, &vArray)); 6618 /* Get values */ 6619 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6620 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6621 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6622 /* Cleanup array */ 6623 PetscCall(VecRestoreArrayRead(v, &vArray)); 6624 } 6625 if (csize) *csize = asize; 6626 /* Cleanup points */ 6627 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6628 PetscFunctionReturn(PETSC_SUCCESS); 6629 } 6630 6631 /*@C 6632 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6633 6634 Not collective 6635 6636 Input Parameters: 6637 + dm - The `DM` 6638 . section - The section describing the layout in `v`, or `NULL` to use the default section 6639 . v - The local vector 6640 - point - The point in the `DM` 6641 6642 Input/Output Parameters: 6643 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6644 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6645 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6646 6647 Level: intermediate 6648 6649 Notes: 6650 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6651 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6652 assembly function, and a user may already have allocated storage for this operation. 6653 6654 A typical use could be 6655 .vb 6656 values = NULL; 6657 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6658 for (cl = 0; cl < clSize; ++cl) { 6659 <Compute on closure> 6660 } 6661 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6662 .ve 6663 or 6664 .vb 6665 PetscMalloc1(clMaxSize, &values); 6666 for (p = pStart; p < pEnd; ++p) { 6667 clSize = clMaxSize; 6668 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6669 for (cl = 0; cl < clSize; ++cl) { 6670 <Compute on closure> 6671 } 6672 } 6673 PetscFree(values); 6674 .ve 6675 6676 Fortran Notes: 6677 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6678 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6679 6680 `values` must be declared with 6681 .vb 6682 PetscScalar,dimension(:),pointer :: values 6683 .ve 6684 and it will be allocated internally by PETSc to hold the values returned 6685 6686 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6687 @*/ 6688 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6689 { 6690 PetscFunctionBeginHot; 6691 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6692 PetscFunctionReturn(PETSC_SUCCESS); 6693 } 6694 6695 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6696 { 6697 DMLabel depthLabel; 6698 PetscSection clSection; 6699 IS clPoints; 6700 PetscScalar *array; 6701 const PetscScalar *vArray; 6702 PetscInt *points = NULL; 6703 const PetscInt *clp, *perm = NULL; 6704 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6705 6706 PetscFunctionBeginHot; 6707 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6708 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6709 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6710 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6711 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6712 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6713 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6714 if (mdepth == 1 && numFields < 2) { 6715 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6716 PetscFunctionReturn(PETSC_SUCCESS); 6717 } 6718 /* Get points */ 6719 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6720 for (clsize = 0, p = 0; p < Np; p++) { 6721 PetscInt dof; 6722 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6723 clsize += dof; 6724 } 6725 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6726 /* Filter points */ 6727 for (p = 0; p < numPoints * 2; p += 2) { 6728 PetscInt dep; 6729 6730 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6731 if (dep != depth) continue; 6732 points[Np * 2 + 0] = points[p]; 6733 points[Np * 2 + 1] = points[p + 1]; 6734 ++Np; 6735 } 6736 /* Get array */ 6737 if (!values || !*values) { 6738 PetscInt asize = 0, dof; 6739 6740 for (p = 0; p < Np * 2; p += 2) { 6741 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6742 asize += dof; 6743 } 6744 if (!values) { 6745 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6746 if (csize) *csize = asize; 6747 PetscFunctionReturn(PETSC_SUCCESS); 6748 } 6749 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6750 } else { 6751 array = *values; 6752 } 6753 PetscCall(VecGetArrayRead(v, &vArray)); 6754 /* Get values */ 6755 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6756 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6757 /* Cleanup points */ 6758 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6759 /* Cleanup array */ 6760 PetscCall(VecRestoreArrayRead(v, &vArray)); 6761 if (!*values) { 6762 if (csize) *csize = size; 6763 *values = array; 6764 } else { 6765 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6766 *csize = size; 6767 } 6768 PetscFunctionReturn(PETSC_SUCCESS); 6769 } 6770 6771 /*@C 6772 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6773 6774 Not collective 6775 6776 Input Parameters: 6777 + dm - The `DM` 6778 . section - The section describing the layout in `v`, or `NULL` to use the default section 6779 . v - The local vector 6780 . point - The point in the `DM` 6781 . csize - The number of values in the closure, or `NULL` 6782 - values - The array of values 6783 6784 Level: intermediate 6785 6786 Note: 6787 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6788 6789 Fortran Note: 6790 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6791 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6792 6793 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6794 @*/ 6795 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6796 { 6797 PetscInt size = 0; 6798 6799 PetscFunctionBegin; 6800 /* Should work without recalculating size */ 6801 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6802 *values = NULL; 6803 PetscFunctionReturn(PETSC_SUCCESS); 6804 } 6805 6806 static inline void add(PetscScalar *x, PetscScalar y) 6807 { 6808 *x += y; 6809 } 6810 static inline void insert(PetscScalar *x, PetscScalar y) 6811 { 6812 *x = y; 6813 } 6814 6815 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[]) 6816 { 6817 PetscInt cdof; /* The number of constraints on this point */ 6818 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6819 PetscScalar *a; 6820 PetscInt off, cind = 0, k; 6821 6822 PetscFunctionBegin; 6823 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6824 PetscCall(PetscSectionGetOffset(section, point, &off)); 6825 a = &array[off]; 6826 if (!cdof || setBC) { 6827 if (clperm) { 6828 if (perm) { 6829 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6830 } else { 6831 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6832 } 6833 } else { 6834 if (perm) { 6835 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6836 } else { 6837 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6838 } 6839 } 6840 } else { 6841 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6842 if (clperm) { 6843 if (perm) { 6844 for (k = 0; k < dof; ++k) { 6845 if ((cind < cdof) && (k == cdofs[cind])) { 6846 ++cind; 6847 continue; 6848 } 6849 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6850 } 6851 } else { 6852 for (k = 0; k < dof; ++k) { 6853 if ((cind < cdof) && (k == cdofs[cind])) { 6854 ++cind; 6855 continue; 6856 } 6857 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6858 } 6859 } 6860 } else { 6861 if (perm) { 6862 for (k = 0; k < dof; ++k) { 6863 if ((cind < cdof) && (k == cdofs[cind])) { 6864 ++cind; 6865 continue; 6866 } 6867 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6868 } 6869 } else { 6870 for (k = 0; k < dof; ++k) { 6871 if ((cind < cdof) && (k == cdofs[cind])) { 6872 ++cind; 6873 continue; 6874 } 6875 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6876 } 6877 } 6878 } 6879 } 6880 PetscFunctionReturn(PETSC_SUCCESS); 6881 } 6882 6883 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[]) 6884 { 6885 PetscInt cdof; /* The number of constraints on this point */ 6886 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6887 PetscScalar *a; 6888 PetscInt off, cind = 0, k; 6889 6890 PetscFunctionBegin; 6891 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6892 PetscCall(PetscSectionGetOffset(section, point, &off)); 6893 a = &array[off]; 6894 if (cdof) { 6895 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6896 if (clperm) { 6897 if (perm) { 6898 for (k = 0; k < dof; ++k) { 6899 if ((cind < cdof) && (k == cdofs[cind])) { 6900 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6901 cind++; 6902 } 6903 } 6904 } else { 6905 for (k = 0; k < dof; ++k) { 6906 if ((cind < cdof) && (k == cdofs[cind])) { 6907 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6908 cind++; 6909 } 6910 } 6911 } 6912 } else { 6913 if (perm) { 6914 for (k = 0; k < dof; ++k) { 6915 if ((cind < cdof) && (k == cdofs[cind])) { 6916 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6917 cind++; 6918 } 6919 } 6920 } else { 6921 for (k = 0; k < dof; ++k) { 6922 if ((cind < cdof) && (k == cdofs[cind])) { 6923 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6924 cind++; 6925 } 6926 } 6927 } 6928 } 6929 } 6930 PetscFunctionReturn(PETSC_SUCCESS); 6931 } 6932 6933 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[]) 6934 { 6935 PetscScalar *a; 6936 PetscInt fdof, foff, fcdof, foffset = *offset; 6937 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6938 PetscInt cind = 0, b; 6939 6940 PetscFunctionBegin; 6941 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6942 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6943 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6944 a = &array[foff]; 6945 if (!fcdof || setBC) { 6946 if (clperm) { 6947 if (perm) { 6948 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6949 } else { 6950 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6951 } 6952 } else { 6953 if (perm) { 6954 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6955 } else { 6956 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6957 } 6958 } 6959 } else { 6960 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6961 if (clperm) { 6962 if (perm) { 6963 for (b = 0; b < fdof; b++) { 6964 if ((cind < fcdof) && (b == fcdofs[cind])) { 6965 ++cind; 6966 continue; 6967 } 6968 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6969 } 6970 } else { 6971 for (b = 0; b < fdof; b++) { 6972 if ((cind < fcdof) && (b == fcdofs[cind])) { 6973 ++cind; 6974 continue; 6975 } 6976 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6977 } 6978 } 6979 } else { 6980 if (perm) { 6981 for (b = 0; b < fdof; b++) { 6982 if ((cind < fcdof) && (b == fcdofs[cind])) { 6983 ++cind; 6984 continue; 6985 } 6986 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6987 } 6988 } else { 6989 for (b = 0; b < fdof; b++) { 6990 if ((cind < fcdof) && (b == fcdofs[cind])) { 6991 ++cind; 6992 continue; 6993 } 6994 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6995 } 6996 } 6997 } 6998 } 6999 *offset += fdof; 7000 PetscFunctionReturn(PETSC_SUCCESS); 7001 } 7002 7003 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[]) 7004 { 7005 PetscScalar *a; 7006 PetscInt fdof, foff, fcdof, foffset = *offset; 7007 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7008 PetscInt Nc, cind = 0, ncind = 0, b; 7009 PetscBool ncSet, fcSet; 7010 7011 PetscFunctionBegin; 7012 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 7013 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7014 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 7015 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 7016 a = &array[foff]; 7017 if (fcdof) { 7018 /* We just override fcdof and fcdofs with Ncc and comps */ 7019 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7020 if (clperm) { 7021 if (perm) { 7022 if (comps) { 7023 for (b = 0; b < fdof; b++) { 7024 ncSet = fcSet = PETSC_FALSE; 7025 if (b % Nc == comps[ncind]) { 7026 ncind = (ncind + 1) % Ncc; 7027 ncSet = PETSC_TRUE; 7028 } 7029 if ((cind < fcdof) && (b == fcdofs[cind])) { 7030 ++cind; 7031 fcSet = PETSC_TRUE; 7032 } 7033 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7034 } 7035 } else { 7036 for (b = 0; b < fdof; b++) { 7037 if ((cind < fcdof) && (b == fcdofs[cind])) { 7038 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7039 ++cind; 7040 } 7041 } 7042 } 7043 } else { 7044 if (comps) { 7045 for (b = 0; b < fdof; b++) { 7046 ncSet = fcSet = PETSC_FALSE; 7047 if (b % Nc == comps[ncind]) { 7048 ncind = (ncind + 1) % Ncc; 7049 ncSet = PETSC_TRUE; 7050 } 7051 if ((cind < fcdof) && (b == fcdofs[cind])) { 7052 ++cind; 7053 fcSet = PETSC_TRUE; 7054 } 7055 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7056 } 7057 } else { 7058 for (b = 0; b < fdof; b++) { 7059 if ((cind < fcdof) && (b == fcdofs[cind])) { 7060 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7061 ++cind; 7062 } 7063 } 7064 } 7065 } 7066 } else { 7067 if (perm) { 7068 if (comps) { 7069 for (b = 0; b < fdof; b++) { 7070 ncSet = fcSet = PETSC_FALSE; 7071 if (b % Nc == comps[ncind]) { 7072 ncind = (ncind + 1) % Ncc; 7073 ncSet = PETSC_TRUE; 7074 } 7075 if ((cind < fcdof) && (b == fcdofs[cind])) { 7076 ++cind; 7077 fcSet = PETSC_TRUE; 7078 } 7079 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7080 } 7081 } else { 7082 for (b = 0; b < fdof; b++) { 7083 if ((cind < fcdof) && (b == fcdofs[cind])) { 7084 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7085 ++cind; 7086 } 7087 } 7088 } 7089 } else { 7090 if (comps) { 7091 for (b = 0; b < fdof; b++) { 7092 ncSet = fcSet = PETSC_FALSE; 7093 if (b % Nc == comps[ncind]) { 7094 ncind = (ncind + 1) % Ncc; 7095 ncSet = PETSC_TRUE; 7096 } 7097 if ((cind < fcdof) && (b == fcdofs[cind])) { 7098 ++cind; 7099 fcSet = PETSC_TRUE; 7100 } 7101 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7102 } 7103 } else { 7104 for (b = 0; b < fdof; b++) { 7105 if ((cind < fcdof) && (b == fcdofs[cind])) { 7106 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7107 ++cind; 7108 } 7109 } 7110 } 7111 } 7112 } 7113 } 7114 *offset += fdof; 7115 PetscFunctionReturn(PETSC_SUCCESS); 7116 } 7117 7118 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7119 { 7120 PetscScalar *array; 7121 const PetscInt *cone, *coneO; 7122 PetscInt pStart, pEnd, p, numPoints, off, dof; 7123 7124 PetscFunctionBeginHot; 7125 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7126 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7127 PetscCall(DMPlexGetCone(dm, point, &cone)); 7128 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7129 PetscCall(VecGetArray(v, &array)); 7130 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7131 const PetscInt cp = !p ? point : cone[p - 1]; 7132 const PetscInt o = !p ? 0 : coneO[p - 1]; 7133 7134 if ((cp < pStart) || (cp >= pEnd)) { 7135 dof = 0; 7136 continue; 7137 } 7138 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7139 /* ADD_VALUES */ 7140 { 7141 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7142 PetscScalar *a; 7143 PetscInt cdof, coff, cind = 0, k; 7144 7145 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7146 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7147 a = &array[coff]; 7148 if (!cdof) { 7149 if (o >= 0) { 7150 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7151 } else { 7152 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7153 } 7154 } else { 7155 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7156 if (o >= 0) { 7157 for (k = 0; k < dof; ++k) { 7158 if ((cind < cdof) && (k == cdofs[cind])) { 7159 ++cind; 7160 continue; 7161 } 7162 a[k] += values[off + k]; 7163 } 7164 } else { 7165 for (k = 0; k < dof; ++k) { 7166 if ((cind < cdof) && (k == cdofs[cind])) { 7167 ++cind; 7168 continue; 7169 } 7170 a[k] += values[off + dof - k - 1]; 7171 } 7172 } 7173 } 7174 } 7175 } 7176 PetscCall(VecRestoreArray(v, &array)); 7177 PetscFunctionReturn(PETSC_SUCCESS); 7178 } 7179 7180 /*@C 7181 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7182 7183 Not collective 7184 7185 Input Parameters: 7186 + dm - The `DM` 7187 . section - The section describing the layout in `v`, or `NULL` to use the default section 7188 . v - The local vector 7189 . point - The point in the `DM` 7190 . values - The array of values 7191 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7192 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7193 7194 Level: intermediate 7195 7196 Note: 7197 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7198 7199 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7200 @*/ 7201 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7202 { 7203 PetscSection clSection; 7204 IS clPoints; 7205 PetscScalar *array; 7206 PetscInt *points = NULL; 7207 const PetscInt *clp, *clperm = NULL; 7208 PetscInt depth, numFields, numPoints, p, clsize; 7209 7210 PetscFunctionBeginHot; 7211 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7212 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7213 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7214 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7215 PetscCall(DMPlexGetDepth(dm, &depth)); 7216 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7217 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7218 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7219 PetscFunctionReturn(PETSC_SUCCESS); 7220 } 7221 /* Get points */ 7222 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7223 for (clsize = 0, p = 0; p < numPoints; p++) { 7224 PetscInt dof; 7225 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7226 clsize += dof; 7227 } 7228 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7229 /* Get array */ 7230 PetscCall(VecGetArray(v, &array)); 7231 /* Get values */ 7232 if (numFields > 0) { 7233 PetscInt offset = 0, f; 7234 for (f = 0; f < numFields; ++f) { 7235 const PetscInt **perms = NULL; 7236 const PetscScalar **flips = NULL; 7237 7238 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7239 switch (mode) { 7240 case INSERT_VALUES: 7241 for (p = 0; p < numPoints; p++) { 7242 const PetscInt point = points[2 * p]; 7243 const PetscInt *perm = perms ? perms[p] : NULL; 7244 const PetscScalar *flip = flips ? flips[p] : NULL; 7245 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7246 } 7247 break; 7248 case INSERT_ALL_VALUES: 7249 for (p = 0; p < numPoints; p++) { 7250 const PetscInt point = points[2 * p]; 7251 const PetscInt *perm = perms ? perms[p] : NULL; 7252 const PetscScalar *flip = flips ? flips[p] : NULL; 7253 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7254 } 7255 break; 7256 case INSERT_BC_VALUES: 7257 for (p = 0; p < numPoints; p++) { 7258 const PetscInt point = points[2 * p]; 7259 const PetscInt *perm = perms ? perms[p] : NULL; 7260 const PetscScalar *flip = flips ? flips[p] : NULL; 7261 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7262 } 7263 break; 7264 case ADD_VALUES: 7265 for (p = 0; p < numPoints; p++) { 7266 const PetscInt point = points[2 * p]; 7267 const PetscInt *perm = perms ? perms[p] : NULL; 7268 const PetscScalar *flip = flips ? flips[p] : NULL; 7269 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7270 } 7271 break; 7272 case ADD_ALL_VALUES: 7273 for (p = 0; p < numPoints; p++) { 7274 const PetscInt point = points[2 * p]; 7275 const PetscInt *perm = perms ? perms[p] : NULL; 7276 const PetscScalar *flip = flips ? flips[p] : NULL; 7277 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7278 } 7279 break; 7280 case ADD_BC_VALUES: 7281 for (p = 0; p < numPoints; p++) { 7282 const PetscInt point = points[2 * p]; 7283 const PetscInt *perm = perms ? perms[p] : NULL; 7284 const PetscScalar *flip = flips ? flips[p] : NULL; 7285 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7286 } 7287 break; 7288 default: 7289 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7290 } 7291 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7292 } 7293 } else { 7294 PetscInt dof, off; 7295 const PetscInt **perms = NULL; 7296 const PetscScalar **flips = NULL; 7297 7298 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7299 switch (mode) { 7300 case INSERT_VALUES: 7301 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7302 const PetscInt point = points[2 * p]; 7303 const PetscInt *perm = perms ? perms[p] : NULL; 7304 const PetscScalar *flip = flips ? flips[p] : NULL; 7305 PetscCall(PetscSectionGetDof(section, point, &dof)); 7306 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7307 } 7308 break; 7309 case INSERT_ALL_VALUES: 7310 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7311 const PetscInt point = points[2 * p]; 7312 const PetscInt *perm = perms ? perms[p] : NULL; 7313 const PetscScalar *flip = flips ? flips[p] : NULL; 7314 PetscCall(PetscSectionGetDof(section, point, &dof)); 7315 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7316 } 7317 break; 7318 case INSERT_BC_VALUES: 7319 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7320 const PetscInt point = points[2 * p]; 7321 const PetscInt *perm = perms ? perms[p] : NULL; 7322 const PetscScalar *flip = flips ? flips[p] : NULL; 7323 PetscCall(PetscSectionGetDof(section, point, &dof)); 7324 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7325 } 7326 break; 7327 case ADD_VALUES: 7328 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7329 const PetscInt point = points[2 * p]; 7330 const PetscInt *perm = perms ? perms[p] : NULL; 7331 const PetscScalar *flip = flips ? flips[p] : NULL; 7332 PetscCall(PetscSectionGetDof(section, point, &dof)); 7333 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7334 } 7335 break; 7336 case ADD_ALL_VALUES: 7337 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7338 const PetscInt point = points[2 * p]; 7339 const PetscInt *perm = perms ? perms[p] : NULL; 7340 const PetscScalar *flip = flips ? flips[p] : NULL; 7341 PetscCall(PetscSectionGetDof(section, point, &dof)); 7342 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7343 } 7344 break; 7345 case ADD_BC_VALUES: 7346 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7347 const PetscInt point = points[2 * p]; 7348 const PetscInt *perm = perms ? perms[p] : NULL; 7349 const PetscScalar *flip = flips ? flips[p] : NULL; 7350 PetscCall(PetscSectionGetDof(section, point, &dof)); 7351 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7352 } 7353 break; 7354 default: 7355 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7356 } 7357 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7358 } 7359 /* Cleanup points */ 7360 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7361 /* Cleanup array */ 7362 PetscCall(VecRestoreArray(v, &array)); 7363 PetscFunctionReturn(PETSC_SUCCESS); 7364 } 7365 7366 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7367 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7368 { 7369 PetscFunctionBegin; 7370 *contains = PETSC_TRUE; 7371 if (label) { 7372 PetscInt fdof; 7373 7374 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7375 if (!*contains) { 7376 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7377 *offset += fdof; 7378 PetscFunctionReturn(PETSC_SUCCESS); 7379 } 7380 } 7381 PetscFunctionReturn(PETSC_SUCCESS); 7382 } 7383 7384 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7385 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) 7386 { 7387 PetscSection clSection; 7388 IS clPoints; 7389 PetscScalar *array; 7390 PetscInt *points = NULL; 7391 const PetscInt *clp; 7392 PetscInt numFields, numPoints, p; 7393 PetscInt offset = 0, f; 7394 7395 PetscFunctionBeginHot; 7396 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7397 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7398 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7399 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7400 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7401 /* Get points */ 7402 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7403 /* Get array */ 7404 PetscCall(VecGetArray(v, &array)); 7405 /* Get values */ 7406 for (f = 0; f < numFields; ++f) { 7407 const PetscInt **perms = NULL; 7408 const PetscScalar **flips = NULL; 7409 PetscBool contains; 7410 7411 if (!fieldActive[f]) { 7412 for (p = 0; p < numPoints * 2; p += 2) { 7413 PetscInt fdof; 7414 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7415 offset += fdof; 7416 } 7417 continue; 7418 } 7419 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7420 switch (mode) { 7421 case INSERT_VALUES: 7422 for (p = 0; p < numPoints; p++) { 7423 const PetscInt point = points[2 * p]; 7424 const PetscInt *perm = perms ? perms[p] : NULL; 7425 const PetscScalar *flip = flips ? flips[p] : NULL; 7426 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7427 if (!contains) continue; 7428 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7429 } 7430 break; 7431 case INSERT_ALL_VALUES: 7432 for (p = 0; p < numPoints; p++) { 7433 const PetscInt point = points[2 * p]; 7434 const PetscInt *perm = perms ? perms[p] : NULL; 7435 const PetscScalar *flip = flips ? flips[p] : NULL; 7436 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7437 if (!contains) continue; 7438 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7439 } 7440 break; 7441 case INSERT_BC_VALUES: 7442 for (p = 0; p < numPoints; p++) { 7443 const PetscInt point = points[2 * p]; 7444 const PetscInt *perm = perms ? perms[p] : NULL; 7445 const PetscScalar *flip = flips ? flips[p] : NULL; 7446 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7447 if (!contains) continue; 7448 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7449 } 7450 break; 7451 case ADD_VALUES: 7452 for (p = 0; p < numPoints; p++) { 7453 const PetscInt point = points[2 * p]; 7454 const PetscInt *perm = perms ? perms[p] : NULL; 7455 const PetscScalar *flip = flips ? flips[p] : NULL; 7456 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7457 if (!contains) continue; 7458 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7459 } 7460 break; 7461 case ADD_ALL_VALUES: 7462 for (p = 0; p < numPoints; p++) { 7463 const PetscInt point = points[2 * p]; 7464 const PetscInt *perm = perms ? perms[p] : NULL; 7465 const PetscScalar *flip = flips ? flips[p] : NULL; 7466 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7467 if (!contains) continue; 7468 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7469 } 7470 break; 7471 default: 7472 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7473 } 7474 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7475 } 7476 /* Cleanup points */ 7477 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7478 /* Cleanup array */ 7479 PetscCall(VecRestoreArray(v, &array)); 7480 PetscFunctionReturn(PETSC_SUCCESS); 7481 } 7482 7483 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7484 { 7485 PetscMPIInt rank; 7486 PetscInt i, j; 7487 7488 PetscFunctionBegin; 7489 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7490 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7491 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7492 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7493 numCIndices = numCIndices ? numCIndices : numRIndices; 7494 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7495 for (i = 0; i < numRIndices; i++) { 7496 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7497 for (j = 0; j < numCIndices; j++) { 7498 #if defined(PETSC_USE_COMPLEX) 7499 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7500 #else 7501 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7502 #endif 7503 } 7504 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7505 } 7506 PetscFunctionReturn(PETSC_SUCCESS); 7507 } 7508 7509 /* 7510 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7511 7512 Input Parameters: 7513 + section - The section for this data layout 7514 . islocal - Is the section (and thus indices being requested) local or global? 7515 . point - The point contributing dofs with these indices 7516 . off - The global offset of this point 7517 . loff - The local offset of each field 7518 . setBC - The flag determining whether to include indices of boundary values 7519 . perm - A permutation of the dofs on this point, or NULL 7520 - indperm - A permutation of the entire indices array, or NULL 7521 7522 Output Parameter: 7523 . indices - Indices for dofs on this point 7524 7525 Level: developer 7526 7527 Note: The indices could be local or global, depending on the value of 'off'. 7528 */ 7529 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7530 { 7531 PetscInt dof; /* The number of unknowns on this point */ 7532 PetscInt cdof; /* The number of constraints on this point */ 7533 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7534 PetscInt cind = 0, k; 7535 7536 PetscFunctionBegin; 7537 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7538 PetscCall(PetscSectionGetDof(section, point, &dof)); 7539 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7540 if (!cdof || setBC) { 7541 for (k = 0; k < dof; ++k) { 7542 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7543 const PetscInt ind = indperm ? indperm[preind] : preind; 7544 7545 indices[ind] = off + k; 7546 } 7547 } else { 7548 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7549 for (k = 0; k < dof; ++k) { 7550 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7551 const PetscInt ind = indperm ? indperm[preind] : preind; 7552 7553 if ((cind < cdof) && (k == cdofs[cind])) { 7554 /* Insert check for returning constrained indices */ 7555 indices[ind] = -(off + k + 1); 7556 ++cind; 7557 } else { 7558 indices[ind] = off + k - (islocal ? 0 : cind); 7559 } 7560 } 7561 } 7562 *loff += dof; 7563 PetscFunctionReturn(PETSC_SUCCESS); 7564 } 7565 7566 /* 7567 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7568 7569 Input Parameters: 7570 + section - a section (global or local) 7571 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7572 . point - point within section 7573 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7574 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7575 . setBC - identify constrained (boundary condition) points via involution. 7576 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7577 . permsoff - offset 7578 - indperm - index permutation 7579 7580 Output Parameter: 7581 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7582 . indices - array to hold indices (as defined by section) of each dof associated with point 7583 7584 Notes: 7585 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7586 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7587 in the local vector. 7588 7589 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7590 significant). It is invalid to call with a global section and setBC=true. 7591 7592 Developer Note: 7593 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7594 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7595 offset could be obtained from the section instead of passing it explicitly as we do now. 7596 7597 Example: 7598 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7599 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7600 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7601 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. 7602 7603 Level: developer 7604 */ 7605 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[]) 7606 { 7607 PetscInt numFields, foff, f; 7608 7609 PetscFunctionBegin; 7610 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7611 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7612 for (f = 0, foff = 0; f < numFields; ++f) { 7613 PetscInt fdof, cfdof; 7614 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7615 PetscInt cind = 0, b; 7616 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7617 7618 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7619 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7620 if (!cfdof || setBC) { 7621 for (b = 0; b < fdof; ++b) { 7622 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7623 const PetscInt ind = indperm ? indperm[preind] : preind; 7624 7625 indices[ind] = off + foff + b; 7626 } 7627 } else { 7628 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7629 for (b = 0; b < fdof; ++b) { 7630 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7631 const PetscInt ind = indperm ? indperm[preind] : preind; 7632 7633 if ((cind < cfdof) && (b == fcdofs[cind])) { 7634 indices[ind] = -(off + foff + b + 1); 7635 ++cind; 7636 } else { 7637 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7638 } 7639 } 7640 } 7641 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7642 foffs[f] += fdof; 7643 } 7644 PetscFunctionReturn(PETSC_SUCCESS); 7645 } 7646 7647 /* 7648 This version believes the globalSection offsets for each field, rather than just the point offset 7649 7650 . foffs - The offset into 'indices' for each field, since it is segregated by field 7651 7652 Notes: 7653 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7654 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7655 */ 7656 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7657 { 7658 PetscInt numFields, foff, f; 7659 7660 PetscFunctionBegin; 7661 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7662 for (f = 0; f < numFields; ++f) { 7663 PetscInt fdof, cfdof; 7664 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7665 PetscInt cind = 0, b; 7666 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7667 7668 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7669 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7670 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7671 if (!cfdof) { 7672 for (b = 0; b < fdof; ++b) { 7673 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7674 const PetscInt ind = indperm ? indperm[preind] : preind; 7675 7676 indices[ind] = foff + b; 7677 } 7678 } else { 7679 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7680 for (b = 0; b < fdof; ++b) { 7681 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7682 const PetscInt ind = indperm ? indperm[preind] : preind; 7683 7684 if ((cind < cfdof) && (b == fcdofs[cind])) { 7685 indices[ind] = -(foff + b + 1); 7686 ++cind; 7687 } else { 7688 indices[ind] = foff + b - cind; 7689 } 7690 } 7691 } 7692 foffs[f] += fdof; 7693 } 7694 PetscFunctionReturn(PETSC_SUCCESS); 7695 } 7696 7697 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7698 { 7699 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7700 7701 PetscFunctionBegin; 7702 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7703 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7704 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7705 for (PetscInt p = 0; p < nPoints; p++) { 7706 PetscInt b = pnts[2 * p]; 7707 PetscInt bSecDof = 0, bOff; 7708 PetscInt cSecDof = 0; 7709 PetscSection indices_section; 7710 7711 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7712 if (!bSecDof) continue; 7713 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7714 indices_section = cSecDof > 0 ? cSec : section; 7715 if (numFields) { 7716 PetscInt fStart[32], fEnd[32]; 7717 7718 fStart[0] = 0; 7719 fEnd[0] = 0; 7720 for (PetscInt f = 0; f < numFields; f++) { 7721 PetscInt fDof = 0; 7722 7723 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7724 fStart[f + 1] = fStart[f] + fDof; 7725 fEnd[f + 1] = fStart[f + 1]; 7726 } 7727 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7728 // only apply permutations on one side 7729 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7730 for (PetscInt f = 0; f < numFields; f++) { 7731 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7732 } 7733 } else { 7734 PetscInt bEnd = 0; 7735 7736 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7737 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7738 7739 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7740 } 7741 } 7742 PetscFunctionReturn(PETSC_SUCCESS); 7743 } 7744 7745 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[]) 7746 { 7747 Mat cMat; 7748 PetscSection aSec, cSec; 7749 IS aIS; 7750 PetscInt aStart = -1, aEnd = -1; 7751 PetscInt sStart = -1, sEnd = -1; 7752 PetscInt cStart = -1, cEnd = -1; 7753 const PetscInt *anchors; 7754 PetscInt numFields, p; 7755 PetscInt newNumPoints = 0, newNumIndices = 0; 7756 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7757 PetscInt oldOffsets[32]; 7758 PetscInt newOffsets[32]; 7759 PetscInt oldOffsetsCopy[32]; 7760 PetscInt newOffsetsCopy[32]; 7761 PetscScalar *modMat = NULL; 7762 PetscBool anyConstrained = PETSC_FALSE; 7763 7764 PetscFunctionBegin; 7765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7766 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7767 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7768 7769 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7770 /* if there are point-to-point constraints */ 7771 if (aSec) { 7772 PetscCall(PetscArrayzero(newOffsets, 32)); 7773 PetscCall(PetscArrayzero(oldOffsets, 32)); 7774 PetscCall(ISGetIndices(aIS, &anchors)); 7775 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7776 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7777 /* figure out how many points are going to be in the new element matrix 7778 * (we allow double counting, because it's all just going to be summed 7779 * into the global matrix anyway) */ 7780 for (p = 0; p < 2 * numPoints; p += 2) { 7781 PetscInt b = points[p]; 7782 PetscInt bDof = 0, bSecDof = 0; 7783 7784 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7785 if (!bSecDof) continue; 7786 7787 for (PetscInt f = 0; f < numFields; f++) { 7788 PetscInt fDof = 0; 7789 7790 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7791 oldOffsets[f + 1] += fDof; 7792 } 7793 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7794 if (bDof) { 7795 /* this point is constrained */ 7796 /* it is going to be replaced by its anchors */ 7797 PetscInt bOff, q; 7798 7799 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7800 for (q = 0; q < bDof; q++) { 7801 PetscInt a = anchors[bOff + q]; 7802 PetscInt aDof = 0; 7803 7804 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7805 if (aDof) { 7806 anyConstrained = PETSC_TRUE; 7807 newNumPoints += 1; 7808 } 7809 newNumIndices += aDof; 7810 for (PetscInt f = 0; f < numFields; ++f) { 7811 PetscInt fDof = 0; 7812 7813 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7814 newOffsets[f + 1] += fDof; 7815 } 7816 } 7817 } else { 7818 /* this point is not constrained */ 7819 newNumPoints++; 7820 newNumIndices += bSecDof; 7821 for (PetscInt f = 0; f < numFields; ++f) { 7822 PetscInt fDof; 7823 7824 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7825 newOffsets[f + 1] += fDof; 7826 } 7827 } 7828 } 7829 } 7830 if (!anyConstrained) { 7831 if (outNumPoints) *outNumPoints = 0; 7832 if (outNumIndices) *outNumIndices = 0; 7833 if (outPoints) *outPoints = NULL; 7834 if (outMat) *outMat = NULL; 7835 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7836 PetscFunctionReturn(PETSC_SUCCESS); 7837 } 7838 7839 if (outNumPoints) *outNumPoints = newNumPoints; 7840 if (outNumIndices) *outNumIndices = newNumIndices; 7841 7842 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7843 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7844 7845 if (!outPoints && !outMat) { 7846 if (offsets) { 7847 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7848 } 7849 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7850 PetscFunctionReturn(PETSC_SUCCESS); 7851 } 7852 7853 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7854 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7855 7856 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7857 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7858 7859 /* output arrays */ 7860 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7861 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7862 7863 // get the new Points 7864 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7865 PetscInt b = points[2 * p]; 7866 PetscInt bDof = 0, bSecDof = 0, bOff; 7867 7868 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7869 if (!bSecDof) continue; 7870 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7871 if (bDof) { 7872 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7873 for (PetscInt q = 0; q < bDof; q++) { 7874 PetscInt a = anchors[bOff + q], aDof = 0; 7875 7876 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7877 if (aDof) { 7878 newPoints[2 * newP] = a; 7879 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7880 newP++; 7881 } 7882 } 7883 } else { 7884 newPoints[2 * newP] = b; 7885 newPoints[2 * newP + 1] = points[2 * p + 1]; 7886 newP++; 7887 } 7888 } 7889 7890 if (outMat) { 7891 PetscScalar *tmpMat; 7892 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7893 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7894 7895 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7896 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7897 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7898 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7899 7900 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7901 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7902 7903 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7904 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7905 7906 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7907 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7908 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7909 // for each field, insert the anchor modification into modMat 7910 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7911 PetscInt fStart = oldOffsets[f]; 7912 PetscInt fNewStart = newOffsets[f]; 7913 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7914 PetscInt b = points[2 * p]; 7915 PetscInt bDof = 0, bSecDof = 0, bOff; 7916 7917 if (b >= sStart && b < sEnd) { 7918 if (numFields) { 7919 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7920 } else { 7921 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7922 } 7923 } 7924 if (!bSecDof) continue; 7925 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7926 if (bDof) { 7927 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7928 for (PetscInt q = 0; q < bDof; q++, newP++) { 7929 PetscInt a = anchors[bOff + q], aDof = 0; 7930 7931 if (a >= sStart && a < sEnd) { 7932 if (numFields) { 7933 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7934 } else { 7935 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7936 } 7937 } 7938 if (aDof) { 7939 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7940 for (PetscInt d = 0; d < bSecDof; d++) { 7941 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7942 } 7943 } 7944 oNew += aDof; 7945 } 7946 } else { 7947 // Insert the identity matrix in this block 7948 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7949 oNew += bSecDof; 7950 newP++; 7951 } 7952 o += bSecDof; 7953 } 7954 } 7955 7956 *outMat = modMat; 7957 7958 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7959 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7960 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7961 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7962 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7963 } 7964 PetscCall(ISRestoreIndices(aIS, &anchors)); 7965 7966 /* output */ 7967 if (outPoints) { 7968 *outPoints = newPoints; 7969 } else { 7970 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7971 } 7972 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7973 PetscFunctionReturn(PETSC_SUCCESS); 7974 } 7975 7976 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) 7977 { 7978 PetscScalar *modMat = NULL; 7979 PetscInt newNumIndices = -1; 7980 7981 PetscFunctionBegin; 7982 /* 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. 7983 modMat is that matrix C */ 7984 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7985 if (outNumIndices) *outNumIndices = newNumIndices; 7986 if (modMat) { 7987 const PetscScalar *newValues = values; 7988 7989 if (multiplyRight) { 7990 PetscScalar *newNewValues = NULL; 7991 PetscBLASInt M, N, K; 7992 PetscScalar a = 1.0, b = 0.0; 7993 7994 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); 7995 7996 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7997 PetscCall(PetscBLASIntCast(numRows, &N)); 7998 PetscCall(PetscBLASIntCast(numIndices, &K)); 7999 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 8000 // row-major to column-major conversion, right multiplication becomes left multiplication 8001 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 8002 numCols = newNumIndices; 8003 newValues = newNewValues; 8004 } 8005 8006 if (multiplyLeft) { 8007 PetscScalar *newNewValues = NULL; 8008 PetscBLASInt M, N, K; 8009 PetscScalar a = 1.0, b = 0.0; 8010 8011 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); 8012 8013 PetscCall(PetscBLASIntCast(numCols, &M)); 8014 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 8015 PetscCall(PetscBLASIntCast(numIndices, &K)); 8016 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 8017 // row-major to column-major conversion, left multiplication becomes right multiplication 8018 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 8019 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 8020 newValues = newNewValues; 8021 } 8022 *outValues = (PetscScalar *)newValues; 8023 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 8024 } 8025 PetscFunctionReturn(PETSC_SUCCESS); 8026 } 8027 8028 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) 8029 { 8030 PetscFunctionBegin; 8031 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 8032 PetscFunctionReturn(PETSC_SUCCESS); 8033 } 8034 8035 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 8036 { 8037 /* Closure ordering */ 8038 PetscSection clSection; 8039 IS clPoints; 8040 const PetscInt *clp; 8041 PetscInt *points; 8042 PetscInt Ncl, Ni = 0; 8043 8044 PetscFunctionBeginHot; 8045 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8046 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 8047 PetscInt dof; 8048 8049 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8050 Ni += dof; 8051 } 8052 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8053 *closureSize = Ni; 8054 PetscFunctionReturn(PETSC_SUCCESS); 8055 } 8056 8057 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) 8058 { 8059 /* Closure ordering */ 8060 PetscSection clSection; 8061 IS clPoints; 8062 const PetscInt *clp; 8063 PetscInt *points; 8064 const PetscInt *clperm = NULL; 8065 /* Dof permutation and sign flips */ 8066 const PetscInt **perms[32] = {NULL}; 8067 const PetscScalar **flips[32] = {NULL}; 8068 PetscScalar *valCopy = NULL; 8069 /* Hanging node constraints */ 8070 PetscInt *pointsC = NULL; 8071 PetscScalar *valuesC = NULL; 8072 PetscInt NclC, NiC; 8073 8074 PetscInt *idx; 8075 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8076 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8077 PetscInt idxStart, idxEnd; 8078 PetscInt nRows, nCols; 8079 8080 PetscFunctionBeginHot; 8081 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8082 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8083 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8084 PetscAssertPointer(numRows, 6); 8085 PetscAssertPointer(numCols, 7); 8086 if (indices) PetscAssertPointer(indices, 8); 8087 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8088 if (values) PetscAssertPointer(values, 10); 8089 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8090 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8091 PetscCall(PetscArrayzero(offsets, 32)); 8092 /* 1) Get points in closure */ 8093 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8094 if (useClPerm) { 8095 PetscInt depth, clsize; 8096 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8097 for (clsize = 0, p = 0; p < Ncl; p++) { 8098 PetscInt dof; 8099 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8100 clsize += dof; 8101 } 8102 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8103 } 8104 /* 2) Get number of indices on these points and field offsets from section */ 8105 for (p = 0; p < Ncl * 2; p += 2) { 8106 PetscInt dof, fdof; 8107 8108 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8109 for (f = 0; f < Nf; ++f) { 8110 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8111 offsets[f + 1] += fdof; 8112 } 8113 Ni += dof; 8114 } 8115 if (*numRows == -1) *numRows = Ni; 8116 if (*numCols == -1) *numCols = Ni; 8117 nRows = *numRows; 8118 nCols = *numCols; 8119 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8120 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8121 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8122 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8123 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8124 for (f = 0; f < PetscMax(1, Nf); ++f) { 8125 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8126 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8127 /* may need to apply sign changes to the element matrix */ 8128 if (values && flips[f]) { 8129 PetscInt foffset = offsets[f]; 8130 8131 for (p = 0; p < Ncl; ++p) { 8132 PetscInt pnt = points[2 * p], fdof; 8133 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8134 8135 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8136 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8137 if (flip) { 8138 PetscInt i, j, k; 8139 8140 if (!valCopy) { 8141 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8142 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8143 *values = valCopy; 8144 } 8145 for (i = 0; i < fdof; ++i) { 8146 PetscScalar fval = flip[i]; 8147 8148 if (multiplyRight) { 8149 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8150 } 8151 if (multiplyLeft) { 8152 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8153 } 8154 } 8155 } 8156 foffset += fdof; 8157 } 8158 } 8159 } 8160 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8161 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8162 if (NclC) { 8163 if (multiplyRight) *numCols = NiC; 8164 if (multiplyLeft) *numRows = NiC; 8165 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8166 for (f = 0; f < PetscMax(1, Nf); ++f) { 8167 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8168 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8169 } 8170 for (f = 0; f < PetscMax(1, Nf); ++f) { 8171 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8172 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8173 } 8174 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8175 Ncl = NclC; 8176 Ni = NiC; 8177 points = pointsC; 8178 if (values) *values = valuesC; 8179 } 8180 /* 5) Calculate indices */ 8181 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8182 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8183 if (Nf) { 8184 PetscInt idxOff; 8185 PetscBool useFieldOffsets; 8186 8187 if (outOffsets) { 8188 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8189 } 8190 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8191 if (useFieldOffsets) { 8192 for (p = 0; p < Ncl; ++p) { 8193 const PetscInt pnt = points[p * 2]; 8194 8195 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8196 } 8197 } else { 8198 for (p = 0; p < Ncl; ++p) { 8199 const PetscInt pnt = points[p * 2]; 8200 8201 if (pnt < idxStart || pnt >= idxEnd) continue; 8202 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8203 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8204 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8205 * global section. */ 8206 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8207 } 8208 } 8209 } else { 8210 PetscInt off = 0, idxOff; 8211 8212 for (p = 0; p < Ncl; ++p) { 8213 const PetscInt pnt = points[p * 2]; 8214 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8215 8216 if (pnt < idxStart || pnt >= idxEnd) continue; 8217 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8218 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8219 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8220 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8221 } 8222 } 8223 /* 6) Cleanup */ 8224 for (f = 0; f < PetscMax(1, Nf); ++f) { 8225 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8226 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8227 } 8228 if (NclC) { 8229 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8230 } else { 8231 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8232 } 8233 8234 if (indices) *indices = idx; 8235 PetscFunctionReturn(PETSC_SUCCESS); 8236 } 8237 8238 /*@C 8239 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8240 8241 Not collective 8242 8243 Input Parameters: 8244 + dm - The `DM` 8245 . section - The `PetscSection` describing the points (a local section) 8246 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8247 . point - The point defining the closure 8248 - useClPerm - Use the closure point permutation if available 8249 8250 Output Parameters: 8251 + numIndices - The number of dof indices in the closure of point with the input sections 8252 . indices - The dof indices 8253 . outOffsets - Array to write the field offsets into, or `NULL` 8254 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8255 8256 Level: advanced 8257 8258 Notes: 8259 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8260 8261 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8262 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8263 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8264 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8265 indices (with the above semantics) are implied. 8266 8267 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8268 `PetscSection`, `DMGetGlobalSection()` 8269 @*/ 8270 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8271 { 8272 PetscInt numRows = -1, numCols = -1; 8273 8274 PetscFunctionBeginHot; 8275 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8276 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8277 *numIndices = numRows; 8278 PetscFunctionReturn(PETSC_SUCCESS); 8279 } 8280 8281 /*@C 8282 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8283 8284 Not collective 8285 8286 Input Parameters: 8287 + dm - The `DM` 8288 . section - The `PetscSection` describing the points (a local section) 8289 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8290 . point - The point defining the closure 8291 - useClPerm - Use the closure point permutation if available 8292 8293 Output Parameters: 8294 + numIndices - The number of dof indices in the closure of point with the input sections 8295 . indices - The dof indices 8296 . outOffsets - Array to write the field offsets into, or `NULL` 8297 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8298 8299 Level: advanced 8300 8301 Notes: 8302 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8303 8304 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8305 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8306 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8307 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8308 indices (with the above semantics) are implied. 8309 8310 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8311 @*/ 8312 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8313 { 8314 PetscFunctionBegin; 8315 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8316 PetscAssertPointer(indices, 7); 8317 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8318 PetscFunctionReturn(PETSC_SUCCESS); 8319 } 8320 8321 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8322 { 8323 DM_Plex *mesh = (DM_Plex *)dm->data; 8324 PetscInt *indices; 8325 PetscInt numIndices; 8326 const PetscScalar *valuesOrig = values; 8327 PetscErrorCode ierr; 8328 8329 PetscFunctionBegin; 8330 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8331 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8332 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8333 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8334 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8335 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8336 8337 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8338 8339 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8340 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8341 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8342 if (ierr) { 8343 PetscMPIInt rank; 8344 8345 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8346 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8347 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8348 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8349 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8350 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8351 } 8352 if (mesh->printFEM > 1) { 8353 PetscInt i; 8354 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8355 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8356 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8357 } 8358 8359 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8360 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8361 PetscFunctionReturn(PETSC_SUCCESS); 8362 } 8363 8364 /*@C 8365 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8366 8367 Not collective 8368 8369 Input Parameters: 8370 + dm - The `DM` 8371 . section - The section describing the layout in `v`, or `NULL` to use the default section 8372 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8373 . A - The matrix 8374 . point - The point in the `DM` 8375 . values - The array of values 8376 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8377 8378 Level: intermediate 8379 8380 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8381 @*/ 8382 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8383 { 8384 PetscFunctionBegin; 8385 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8386 PetscFunctionReturn(PETSC_SUCCESS); 8387 } 8388 8389 /*@C 8390 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8391 8392 Not collective 8393 8394 Input Parameters: 8395 + dmRow - The `DM` for the row fields 8396 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8397 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8398 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8399 . dmCol - The `DM` for the column fields 8400 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8401 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8402 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8403 . A - The matrix 8404 . point - The point in the `DM` 8405 . values - The array of values 8406 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8407 8408 Level: intermediate 8409 8410 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8411 @*/ 8412 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) 8413 { 8414 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8415 PetscInt *indicesRow, *indicesCol; 8416 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8417 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8418 8419 PetscErrorCode ierr; 8420 8421 PetscFunctionBegin; 8422 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8423 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8424 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8425 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8426 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8427 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8428 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8429 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8430 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8431 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8432 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8433 8434 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8435 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8436 valuesV1 = valuesV0; 8437 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8438 valuesV2 = valuesV1; 8439 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8440 8441 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8442 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8443 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8444 if (ierr) { 8445 PetscMPIInt rank; 8446 8447 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8448 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8449 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8450 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8451 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8452 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8453 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8454 } 8455 8456 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8457 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8458 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8459 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8460 PetscFunctionReturn(PETSC_SUCCESS); 8461 } 8462 8463 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8464 { 8465 DM_Plex *mesh = (DM_Plex *)dmf->data; 8466 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8467 PetscInt *cpoints = NULL; 8468 PetscInt *findices, *cindices; 8469 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8470 PetscInt foffsets[32], coffsets[32]; 8471 DMPolytopeType ct; 8472 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8473 PetscErrorCode ierr; 8474 8475 PetscFunctionBegin; 8476 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8477 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8478 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8479 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8480 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8481 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8482 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8483 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8484 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8485 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8486 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8487 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8488 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8489 PetscCall(PetscArrayzero(foffsets, 32)); 8490 PetscCall(PetscArrayzero(coffsets, 32)); 8491 /* Column indices */ 8492 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8493 maxFPoints = numCPoints; 8494 /* Compress out points not in the section */ 8495 /* TODO: Squeeze out points with 0 dof as well */ 8496 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8497 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8498 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8499 cpoints[q * 2] = cpoints[p]; 8500 cpoints[q * 2 + 1] = cpoints[p + 1]; 8501 ++q; 8502 } 8503 } 8504 numCPoints = q; 8505 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8506 PetscInt fdof; 8507 8508 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8509 if (!dof) continue; 8510 for (f = 0; f < numFields; ++f) { 8511 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8512 coffsets[f + 1] += fdof; 8513 } 8514 numCIndices += dof; 8515 } 8516 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8517 /* Row indices */ 8518 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8519 { 8520 DMPlexTransform tr; 8521 DMPolytopeType *rct; 8522 PetscInt *rsize, *rcone, *rornt, Nt; 8523 8524 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8525 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8526 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8527 numSubcells = rsize[Nt - 1]; 8528 PetscCall(DMPlexTransformDestroy(&tr)); 8529 } 8530 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8531 for (r = 0, q = 0; r < numSubcells; ++r) { 8532 /* TODO Map from coarse to fine cells */ 8533 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8534 /* Compress out points not in the section */ 8535 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8536 for (p = 0; p < numFPoints * 2; p += 2) { 8537 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8538 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8539 if (!dof) continue; 8540 for (s = 0; s < q; ++s) 8541 if (fpoints[p] == ftotpoints[s * 2]) break; 8542 if (s < q) continue; 8543 ftotpoints[q * 2] = fpoints[p]; 8544 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8545 ++q; 8546 } 8547 } 8548 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8549 } 8550 numFPoints = q; 8551 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8552 PetscInt fdof; 8553 8554 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8555 if (!dof) continue; 8556 for (f = 0; f < numFields; ++f) { 8557 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8558 foffsets[f + 1] += fdof; 8559 } 8560 numFIndices += dof; 8561 } 8562 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8563 8564 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8565 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8566 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8567 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8568 if (numFields) { 8569 const PetscInt **permsF[32] = {NULL}; 8570 const PetscInt **permsC[32] = {NULL}; 8571 8572 for (f = 0; f < numFields; f++) { 8573 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8574 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8575 } 8576 for (p = 0; p < numFPoints; p++) { 8577 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8578 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8579 } 8580 for (p = 0; p < numCPoints; p++) { 8581 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8582 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8583 } 8584 for (f = 0; f < numFields; f++) { 8585 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8586 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8587 } 8588 } else { 8589 const PetscInt **permsF = NULL; 8590 const PetscInt **permsC = NULL; 8591 8592 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8593 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8594 for (p = 0, off = 0; p < numFPoints; p++) { 8595 const PetscInt *perm = permsF ? permsF[p] : NULL; 8596 8597 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8598 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8599 } 8600 for (p = 0, off = 0; p < numCPoints; p++) { 8601 const PetscInt *perm = permsC ? permsC[p] : NULL; 8602 8603 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8604 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8605 } 8606 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8607 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8608 } 8609 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8610 /* TODO: flips */ 8611 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8612 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8613 if (ierr) { 8614 PetscMPIInt rank; 8615 8616 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8617 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8618 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8619 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8620 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8621 } 8622 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8623 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8624 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8625 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8626 PetscFunctionReturn(PETSC_SUCCESS); 8627 } 8628 8629 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8630 { 8631 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8632 PetscInt *cpoints = NULL; 8633 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8634 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8635 DMPolytopeType ct; 8636 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8637 8638 PetscFunctionBegin; 8639 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8640 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8641 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8642 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8643 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8644 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8645 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8646 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8647 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8648 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8649 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8650 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8651 /* Column indices */ 8652 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8653 maxFPoints = numCPoints; 8654 /* Compress out points not in the section */ 8655 /* TODO: Squeeze out points with 0 dof as well */ 8656 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8657 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8658 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8659 cpoints[q * 2] = cpoints[p]; 8660 cpoints[q * 2 + 1] = cpoints[p + 1]; 8661 ++q; 8662 } 8663 } 8664 numCPoints = q; 8665 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8666 PetscInt fdof; 8667 8668 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8669 if (!dof) continue; 8670 for (f = 0; f < numFields; ++f) { 8671 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8672 coffsets[f + 1] += fdof; 8673 } 8674 numCIndices += dof; 8675 } 8676 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8677 /* Row indices */ 8678 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8679 { 8680 DMPlexTransform tr; 8681 DMPolytopeType *rct; 8682 PetscInt *rsize, *rcone, *rornt, Nt; 8683 8684 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8685 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8686 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8687 numSubcells = rsize[Nt - 1]; 8688 PetscCall(DMPlexTransformDestroy(&tr)); 8689 } 8690 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8691 for (r = 0, q = 0; r < numSubcells; ++r) { 8692 /* TODO Map from coarse to fine cells */ 8693 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8694 /* Compress out points not in the section */ 8695 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8696 for (p = 0; p < numFPoints * 2; p += 2) { 8697 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8698 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8699 if (!dof) continue; 8700 for (s = 0; s < q; ++s) 8701 if (fpoints[p] == ftotpoints[s * 2]) break; 8702 if (s < q) continue; 8703 ftotpoints[q * 2] = fpoints[p]; 8704 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8705 ++q; 8706 } 8707 } 8708 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8709 } 8710 numFPoints = q; 8711 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8712 PetscInt fdof; 8713 8714 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8715 if (!dof) continue; 8716 for (f = 0; f < numFields; ++f) { 8717 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8718 foffsets[f + 1] += fdof; 8719 } 8720 numFIndices += dof; 8721 } 8722 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8723 8724 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8725 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8726 if (numFields) { 8727 const PetscInt **permsF[32] = {NULL}; 8728 const PetscInt **permsC[32] = {NULL}; 8729 8730 for (f = 0; f < numFields; f++) { 8731 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8732 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8733 } 8734 for (p = 0; p < numFPoints; p++) { 8735 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8736 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8737 } 8738 for (p = 0; p < numCPoints; p++) { 8739 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8740 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8741 } 8742 for (f = 0; f < numFields; f++) { 8743 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8744 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8745 } 8746 } else { 8747 const PetscInt **permsF = NULL; 8748 const PetscInt **permsC = NULL; 8749 8750 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8751 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8752 for (p = 0, off = 0; p < numFPoints; p++) { 8753 const PetscInt *perm = permsF ? permsF[p] : NULL; 8754 8755 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8756 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8757 } 8758 for (p = 0, off = 0; p < numCPoints; p++) { 8759 const PetscInt *perm = permsC ? permsC[p] : NULL; 8760 8761 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8762 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8763 } 8764 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8765 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8766 } 8767 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8768 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8769 PetscFunctionReturn(PETSC_SUCCESS); 8770 } 8771 8772 /*@ 8773 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8774 8775 Input Parameter: 8776 . dm - The `DMPLEX` object 8777 8778 Output Parameter: 8779 . cellHeight - The height of a cell 8780 8781 Level: developer 8782 8783 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8784 @*/ 8785 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8786 { 8787 DM_Plex *mesh = (DM_Plex *)dm->data; 8788 8789 PetscFunctionBegin; 8790 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8791 PetscAssertPointer(cellHeight, 2); 8792 *cellHeight = mesh->vtkCellHeight; 8793 PetscFunctionReturn(PETSC_SUCCESS); 8794 } 8795 8796 /*@ 8797 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8798 8799 Input Parameters: 8800 + dm - The `DMPLEX` object 8801 - cellHeight - The height of a cell 8802 8803 Level: developer 8804 8805 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8806 @*/ 8807 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8808 { 8809 DM_Plex *mesh = (DM_Plex *)dm->data; 8810 8811 PetscFunctionBegin; 8812 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8813 mesh->vtkCellHeight = cellHeight; 8814 PetscFunctionReturn(PETSC_SUCCESS); 8815 } 8816 8817 /*@ 8818 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8819 8820 Input Parameters: 8821 + dm - The `DMPLEX` object 8822 - ct - The `DMPolytopeType` of the cell 8823 8824 Output Parameters: 8825 + start - The first cell of this type, or `NULL` 8826 - end - The upper bound on this celltype, or `NULL` 8827 8828 Level: advanced 8829 8830 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8831 @*/ 8832 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end) 8833 { 8834 DM_Plex *mesh = (DM_Plex *)dm->data; 8835 DMLabel label; 8836 PetscInt pStart, pEnd; 8837 8838 PetscFunctionBegin; 8839 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8840 if (start) { 8841 PetscAssertPointer(start, 3); 8842 *start = 0; 8843 } 8844 if (end) { 8845 PetscAssertPointer(end, 4); 8846 *end = 0; 8847 } 8848 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8849 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8850 if (mesh->tr) { 8851 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8852 } else { 8853 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8854 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8855 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8856 } 8857 PetscFunctionReturn(PETSC_SUCCESS); 8858 } 8859 8860 /*@ 8861 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8862 8863 Input Parameters: 8864 + dm - The `DMPLEX` object 8865 - depth - The depth for the given point stratum 8866 8867 Output Parameter: 8868 . gsize - The global number of points in the stratum 8869 8870 Level: advanced 8871 8872 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8873 @*/ 8874 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8875 { 8876 PetscSF sf; 8877 const PetscInt *leaves; 8878 PetscInt Nl, loc, start, end, lsize = 0; 8879 8880 PetscFunctionBegin; 8881 PetscCall(DMGetPointSF(dm, &sf)); 8882 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8883 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8884 for (PetscInt p = start; p < end; ++p) { 8885 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8886 if (loc < 0) ++lsize; 8887 } 8888 PetscCallMPI(MPI_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8889 PetscFunctionReturn(PETSC_SUCCESS); 8890 } 8891 8892 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8893 { 8894 PetscSection section, globalSection; 8895 PetscInt *numbers, p; 8896 8897 PetscFunctionBegin; 8898 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8899 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8900 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8901 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8902 PetscCall(PetscSectionSetUp(section)); 8903 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8904 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8905 for (p = pStart; p < pEnd; ++p) { 8906 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8907 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8908 else numbers[p - pStart] += shift; 8909 } 8910 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8911 if (globalSize) { 8912 PetscLayout layout; 8913 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8914 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8915 PetscCall(PetscLayoutDestroy(&layout)); 8916 } 8917 PetscCall(PetscSectionDestroy(§ion)); 8918 PetscCall(PetscSectionDestroy(&globalSection)); 8919 PetscFunctionReturn(PETSC_SUCCESS); 8920 } 8921 8922 /*@ 8923 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8924 8925 Input Parameters: 8926 + dm - The `DMPLEX` object 8927 - includeAll - Whether to include all cells, or just the simplex and box cells 8928 8929 Output Parameter: 8930 . globalCellNumbers - Global cell numbers for all cells on this process 8931 8932 Level: developer 8933 8934 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8935 @*/ 8936 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8937 { 8938 PetscInt cellHeight, cStart, cEnd; 8939 8940 PetscFunctionBegin; 8941 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8942 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8943 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8944 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8945 PetscFunctionReturn(PETSC_SUCCESS); 8946 } 8947 8948 /*@ 8949 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8950 8951 Input Parameter: 8952 . dm - The `DMPLEX` object 8953 8954 Output Parameter: 8955 . globalCellNumbers - Global cell numbers for all cells on this process 8956 8957 Level: developer 8958 8959 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8960 @*/ 8961 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8962 { 8963 DM_Plex *mesh = (DM_Plex *)dm->data; 8964 8965 PetscFunctionBegin; 8966 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8967 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8968 *globalCellNumbers = mesh->globalCellNumbers; 8969 PetscFunctionReturn(PETSC_SUCCESS); 8970 } 8971 8972 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8973 { 8974 PetscInt vStart, vEnd; 8975 8976 PetscFunctionBegin; 8977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8978 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8979 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8980 PetscFunctionReturn(PETSC_SUCCESS); 8981 } 8982 8983 /*@ 8984 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8985 8986 Input Parameter: 8987 . dm - The `DMPLEX` object 8988 8989 Output Parameter: 8990 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8991 8992 Level: developer 8993 8994 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8995 @*/ 8996 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8997 { 8998 DM_Plex *mesh = (DM_Plex *)dm->data; 8999 9000 PetscFunctionBegin; 9001 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9002 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 9003 *globalVertexNumbers = mesh->globalVertexNumbers; 9004 PetscFunctionReturn(PETSC_SUCCESS); 9005 } 9006 9007 /*@ 9008 DMPlexCreatePointNumbering - Create a global numbering for all points. 9009 9010 Collective 9011 9012 Input Parameter: 9013 . dm - The `DMPLEX` object 9014 9015 Output Parameter: 9016 . globalPointNumbers - Global numbers for all points on this process 9017 9018 Level: developer 9019 9020 Notes: 9021 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 9022 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 9023 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 9024 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 9025 9026 The partitioned mesh is 9027 ``` 9028 (2)--0--(3)--1--(4) (1)--0--(2) 9029 ``` 9030 and its global numbering is 9031 ``` 9032 (3)--0--(4)--1--(5)--2--(6) 9033 ``` 9034 Then the global numbering is provided as 9035 ``` 9036 [0] Number of indices in set 5 9037 [0] 0 0 9038 [0] 1 1 9039 [0] 2 3 9040 [0] 3 4 9041 [0] 4 -6 9042 [1] Number of indices in set 3 9043 [1] 0 2 9044 [1] 1 5 9045 [1] 2 6 9046 ``` 9047 9048 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9049 @*/ 9050 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 9051 { 9052 IS nums[4]; 9053 PetscInt depths[4], gdepths[4], starts[4]; 9054 PetscInt depth, d, shift = 0; 9055 PetscBool empty = PETSC_FALSE; 9056 9057 PetscFunctionBegin; 9058 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9059 PetscCall(DMPlexGetDepth(dm, &depth)); 9060 // For unstratified meshes use dim instead of depth 9061 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9062 // If any stratum is empty, we must mark all empty 9063 for (d = 0; d <= depth; ++d) { 9064 PetscInt end; 9065 9066 depths[d] = depth - d; 9067 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9068 if (!(starts[d] - end)) empty = PETSC_TRUE; 9069 } 9070 if (empty) 9071 for (d = 0; d <= depth; ++d) { 9072 depths[d] = -1; 9073 starts[d] = -1; 9074 } 9075 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9076 PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9077 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]); 9078 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9079 for (d = 0; d <= depth; ++d) { 9080 PetscInt pStart, pEnd, gsize; 9081 9082 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9083 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9084 shift += gsize; 9085 } 9086 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9087 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9088 PetscFunctionReturn(PETSC_SUCCESS); 9089 } 9090 9091 /*@ 9092 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9093 9094 Collective 9095 9096 Input Parameter: 9097 . dm - The `DMPLEX` object 9098 9099 Output Parameter: 9100 . globalEdgeNumbers - Global numbers for all edges on this process 9101 9102 Level: developer 9103 9104 Notes: 9105 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). 9106 9107 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9108 @*/ 9109 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9110 { 9111 PetscSF sf; 9112 PetscInt eStart, eEnd; 9113 9114 PetscFunctionBegin; 9115 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9116 PetscCall(DMGetPointSF(dm, &sf)); 9117 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9118 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9119 PetscFunctionReturn(PETSC_SUCCESS); 9120 } 9121 9122 /*@ 9123 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9124 9125 Input Parameter: 9126 . dm - The `DMPLEX` object 9127 9128 Output Parameter: 9129 . ranks - The rank field 9130 9131 Options Database Key: 9132 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9133 9134 Level: intermediate 9135 9136 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9137 @*/ 9138 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9139 { 9140 DM rdm; 9141 PetscFE fe; 9142 PetscScalar *r; 9143 PetscMPIInt rank; 9144 DMPolytopeType ct; 9145 PetscInt dim, cStart, cEnd, c; 9146 PetscBool simplex; 9147 9148 PetscFunctionBeginUser; 9149 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9150 PetscAssertPointer(ranks, 2); 9151 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9152 PetscCall(DMClone(dm, &rdm)); 9153 PetscCall(DMGetDimension(rdm, &dim)); 9154 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9155 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9156 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9157 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9158 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9159 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9160 PetscCall(PetscFEDestroy(&fe)); 9161 PetscCall(DMCreateDS(rdm)); 9162 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9163 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9164 PetscCall(VecGetArray(*ranks, &r)); 9165 for (c = cStart; c < cEnd; ++c) { 9166 PetscScalar *lr; 9167 9168 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9169 if (lr) *lr = rank; 9170 } 9171 PetscCall(VecRestoreArray(*ranks, &r)); 9172 PetscCall(DMDestroy(&rdm)); 9173 PetscFunctionReturn(PETSC_SUCCESS); 9174 } 9175 9176 /*@ 9177 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9178 9179 Input Parameters: 9180 + dm - The `DMPLEX` 9181 - label - The `DMLabel` 9182 9183 Output Parameter: 9184 . val - The label value field 9185 9186 Options Database Key: 9187 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9188 9189 Level: intermediate 9190 9191 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9192 @*/ 9193 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9194 { 9195 DM rdm, plex; 9196 Vec lval; 9197 PetscSection section; 9198 PetscFE fe; 9199 PetscScalar *v; 9200 PetscInt dim, pStart, pEnd, p, cStart; 9201 DMPolytopeType ct; 9202 char name[PETSC_MAX_PATH_LEN]; 9203 const char *lname, *prefix; 9204 9205 PetscFunctionBeginUser; 9206 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9207 PetscAssertPointer(label, 2); 9208 PetscAssertPointer(val, 3); 9209 PetscCall(DMClone(dm, &rdm)); 9210 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9211 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9212 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9213 PetscCall(DMDestroy(&plex)); 9214 PetscCall(DMGetDimension(rdm, &dim)); 9215 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9216 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9217 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9218 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9219 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9220 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9221 PetscCall(PetscFEDestroy(&fe)); 9222 PetscCall(DMCreateDS(rdm)); 9223 PetscCall(DMCreateGlobalVector(rdm, val)); 9224 PetscCall(DMCreateLocalVector(rdm, &lval)); 9225 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9226 PetscCall(DMGetLocalSection(rdm, §ion)); 9227 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9228 PetscCall(VecGetArray(lval, &v)); 9229 for (p = pStart; p < pEnd; ++p) { 9230 PetscInt cval, dof, off; 9231 9232 PetscCall(PetscSectionGetDof(section, p, &dof)); 9233 if (!dof) continue; 9234 PetscCall(DMLabelGetValue(label, p, &cval)); 9235 PetscCall(PetscSectionGetOffset(section, p, &off)); 9236 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9237 } 9238 PetscCall(VecRestoreArray(lval, &v)); 9239 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9240 PetscCall(VecDestroy(&lval)); 9241 PetscCall(DMDestroy(&rdm)); 9242 PetscFunctionReturn(PETSC_SUCCESS); 9243 } 9244 9245 /*@ 9246 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9247 9248 Input Parameter: 9249 . dm - The `DMPLEX` object 9250 9251 Level: developer 9252 9253 Notes: 9254 This is a useful diagnostic when creating meshes programmatically. 9255 9256 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9257 9258 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9259 @*/ 9260 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9261 { 9262 PetscSection coneSection, supportSection; 9263 const PetscInt *cone, *support; 9264 PetscInt coneSize, c, supportSize, s; 9265 PetscInt pStart, pEnd, p, pp, csize, ssize; 9266 PetscBool storagecheck = PETSC_TRUE; 9267 9268 PetscFunctionBegin; 9269 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9270 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9271 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9272 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9273 /* Check that point p is found in the support of its cone points, and vice versa */ 9274 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9275 for (p = pStart; p < pEnd; ++p) { 9276 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9277 PetscCall(DMPlexGetCone(dm, p, &cone)); 9278 for (c = 0; c < coneSize; ++c) { 9279 PetscBool dup = PETSC_FALSE; 9280 PetscInt d; 9281 for (d = c - 1; d >= 0; --d) { 9282 if (cone[c] == cone[d]) { 9283 dup = PETSC_TRUE; 9284 break; 9285 } 9286 } 9287 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9288 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9289 for (s = 0; s < supportSize; ++s) { 9290 if (support[s] == p) break; 9291 } 9292 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9293 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9294 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9295 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9296 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9297 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9298 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9299 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]); 9300 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9301 } 9302 } 9303 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9304 if (p != pp) { 9305 storagecheck = PETSC_FALSE; 9306 continue; 9307 } 9308 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9309 PetscCall(DMPlexGetSupport(dm, p, &support)); 9310 for (s = 0; s < supportSize; ++s) { 9311 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9312 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9313 for (c = 0; c < coneSize; ++c) { 9314 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9315 if (cone[c] != pp) { 9316 c = 0; 9317 break; 9318 } 9319 if (cone[c] == p) break; 9320 } 9321 if (c >= coneSize) { 9322 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9323 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9324 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9325 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9326 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9327 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9328 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9329 } 9330 } 9331 } 9332 if (storagecheck) { 9333 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9334 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9335 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9336 } 9337 PetscFunctionReturn(PETSC_SUCCESS); 9338 } 9339 9340 /* 9341 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. 9342 */ 9343 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9344 { 9345 DMPolytopeType cct; 9346 PetscInt ptpoints[4]; 9347 const PetscInt *cone, *ccone, *ptcone; 9348 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9349 9350 PetscFunctionBegin; 9351 *unsplit = 0; 9352 switch (ct) { 9353 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9354 ptpoints[npt++] = c; 9355 break; 9356 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9357 PetscCall(DMPlexGetCone(dm, c, &cone)); 9358 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9359 for (cp = 0; cp < coneSize; ++cp) { 9360 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9361 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9362 } 9363 break; 9364 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9365 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9366 PetscCall(DMPlexGetCone(dm, c, &cone)); 9367 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9368 for (cp = 0; cp < coneSize; ++cp) { 9369 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9370 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9371 for (ccp = 0; ccp < cconeSize; ++ccp) { 9372 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9373 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9374 PetscInt p; 9375 for (p = 0; p < npt; ++p) 9376 if (ptpoints[p] == ccone[ccp]) break; 9377 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9378 } 9379 } 9380 } 9381 break; 9382 default: 9383 break; 9384 } 9385 for (pt = 0; pt < npt; ++pt) { 9386 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9387 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9388 } 9389 PetscFunctionReturn(PETSC_SUCCESS); 9390 } 9391 9392 /*@ 9393 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9394 9395 Input Parameters: 9396 + dm - The `DMPLEX` object 9397 - cellHeight - Normally 0 9398 9399 Level: developer 9400 9401 Notes: 9402 This is a useful diagnostic when creating meshes programmatically. 9403 Currently applicable only to homogeneous simplex or tensor meshes. 9404 9405 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9406 9407 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9408 @*/ 9409 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9410 { 9411 DMPlexInterpolatedFlag interp; 9412 DMPolytopeType ct; 9413 PetscInt vStart, vEnd, cStart, cEnd, c; 9414 9415 PetscFunctionBegin; 9416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9417 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9418 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9419 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9420 for (c = cStart; c < cEnd; ++c) { 9421 PetscInt *closure = NULL; 9422 PetscInt coneSize, closureSize, cl, Nv = 0; 9423 9424 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9425 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9426 if (interp == DMPLEX_INTERPOLATED_FULL) { 9427 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9428 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)); 9429 } 9430 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9431 for (cl = 0; cl < closureSize * 2; cl += 2) { 9432 const PetscInt p = closure[cl]; 9433 if ((p >= vStart) && (p < vEnd)) ++Nv; 9434 } 9435 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9436 /* Special Case: Tensor faces with identified vertices */ 9437 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9438 PetscInt unsplit; 9439 9440 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9441 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9442 } 9443 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)); 9444 } 9445 PetscFunctionReturn(PETSC_SUCCESS); 9446 } 9447 9448 /*@ 9449 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9450 9451 Collective 9452 9453 Input Parameters: 9454 + dm - The `DMPLEX` object 9455 - cellHeight - Normally 0 9456 9457 Level: developer 9458 9459 Notes: 9460 This is a useful diagnostic when creating meshes programmatically. 9461 This routine is only relevant for meshes that are fully interpolated across all ranks. 9462 It will error out if a partially interpolated mesh is given on some rank. 9463 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9464 9465 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9466 9467 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9468 @*/ 9469 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9470 { 9471 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9472 DMPlexInterpolatedFlag interpEnum; 9473 9474 PetscFunctionBegin; 9475 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9476 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9477 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9478 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9479 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9480 PetscFunctionReturn(PETSC_SUCCESS); 9481 } 9482 9483 PetscCall(DMGetDimension(dm, &dim)); 9484 PetscCall(DMPlexGetDepth(dm, &depth)); 9485 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9486 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9487 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9488 for (c = cStart; c < cEnd; ++c) { 9489 const PetscInt *cone, *ornt, *faceSizes, *faces; 9490 const DMPolytopeType *faceTypes; 9491 DMPolytopeType ct; 9492 PetscInt numFaces, coneSize, f; 9493 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9494 9495 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9496 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9497 if (unsplit) continue; 9498 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9499 PetscCall(DMPlexGetCone(dm, c, &cone)); 9500 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9501 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9502 for (cl = 0; cl < closureSize * 2; cl += 2) { 9503 const PetscInt p = closure[cl]; 9504 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9505 } 9506 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9507 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); 9508 for (f = 0; f < numFaces; ++f) { 9509 DMPolytopeType fct; 9510 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9511 9512 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9513 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9514 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9515 const PetscInt p = fclosure[cl]; 9516 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9517 } 9518 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]); 9519 for (v = 0; v < fnumCorners; ++v) { 9520 if (fclosure[v] != faces[fOff + v]) { 9521 PetscInt v1; 9522 9523 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9524 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9525 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9526 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9527 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9528 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]); 9529 } 9530 } 9531 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9532 fOff += faceSizes[f]; 9533 } 9534 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9535 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9536 } 9537 } 9538 PetscFunctionReturn(PETSC_SUCCESS); 9539 } 9540 9541 /*@ 9542 DMPlexCheckGeometry - Check the geometry of mesh cells 9543 9544 Input Parameter: 9545 . dm - The `DMPLEX` object 9546 9547 Level: developer 9548 9549 Notes: 9550 This is a useful diagnostic when creating meshes programmatically. 9551 9552 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9553 9554 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9555 @*/ 9556 PetscErrorCode DMPlexCheckGeometry(DM dm) 9557 { 9558 Vec coordinates; 9559 PetscReal detJ, J[9], refVol = 1.0; 9560 PetscReal vol; 9561 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9562 9563 PetscFunctionBegin; 9564 PetscCall(DMGetDimension(dm, &dim)); 9565 PetscCall(DMGetCoordinateDim(dm, &dE)); 9566 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9567 PetscCall(DMPlexGetDepth(dm, &depth)); 9568 for (d = 0; d < dim; ++d) refVol *= 2.0; 9569 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9570 /* Make sure local coordinates are created, because that step is collective */ 9571 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9572 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9573 for (c = cStart; c < cEnd; ++c) { 9574 DMPolytopeType ct; 9575 PetscInt unsplit; 9576 PetscBool ignoreZeroVol = PETSC_FALSE; 9577 9578 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9579 switch (ct) { 9580 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9581 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9582 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9583 ignoreZeroVol = PETSC_TRUE; 9584 break; 9585 default: 9586 break; 9587 } 9588 switch (ct) { 9589 case DM_POLYTOPE_TRI_PRISM: 9590 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9591 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9592 case DM_POLYTOPE_PYRAMID: 9593 continue; 9594 default: 9595 break; 9596 } 9597 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9598 if (unsplit) continue; 9599 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9600 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); 9601 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9602 /* This should work with periodicity since DG coordinates should be used */ 9603 if (depth > 1) { 9604 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9605 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); 9606 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9607 } 9608 } 9609 PetscFunctionReturn(PETSC_SUCCESS); 9610 } 9611 9612 /*@ 9613 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9614 9615 Collective 9616 9617 Input Parameters: 9618 + dm - The `DMPLEX` object 9619 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9620 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9621 9622 Level: developer 9623 9624 Notes: 9625 This is mainly intended for debugging/testing purposes. 9626 9627 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9628 9629 Extra roots can come from periodic cuts, where additional points appear on the boundary 9630 9631 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9632 @*/ 9633 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9634 { 9635 PetscInt l, nleaves, nroots, overlap; 9636 const PetscInt *locals; 9637 const PetscSFNode *remotes; 9638 PetscBool distributed; 9639 MPI_Comm comm; 9640 PetscMPIInt rank; 9641 9642 PetscFunctionBegin; 9643 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9644 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9645 else pointSF = dm->sf; 9646 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9647 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9648 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9649 { 9650 PetscMPIInt mpiFlag; 9651 9652 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9653 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9654 } 9655 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9656 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9657 if (!distributed) { 9658 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); 9659 PetscFunctionReturn(PETSC_SUCCESS); 9660 } 9661 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); 9662 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9663 9664 /* Check SF graph is compatible with DMPlex chart */ 9665 { 9666 PetscInt pStart, pEnd, maxLeaf; 9667 9668 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9669 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9670 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9671 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9672 } 9673 9674 /* Check there are no cells in interface */ 9675 if (!overlap) { 9676 PetscInt cellHeight, cStart, cEnd; 9677 9678 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9679 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9680 for (l = 0; l < nleaves; ++l) { 9681 const PetscInt point = locals ? locals[l] : l; 9682 9683 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9684 } 9685 } 9686 9687 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9688 { 9689 const PetscInt *rootdegree; 9690 9691 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9692 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9693 for (l = 0; l < nleaves; ++l) { 9694 const PetscInt point = locals ? locals[l] : l; 9695 const PetscInt *cone; 9696 PetscInt coneSize, c, idx; 9697 9698 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9699 PetscCall(DMPlexGetCone(dm, point, &cone)); 9700 for (c = 0; c < coneSize; ++c) { 9701 if (!rootdegree[cone[c]]) { 9702 if (locals) { 9703 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9704 } else { 9705 idx = (cone[c] < nleaves) ? cone[c] : -1; 9706 } 9707 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9708 } 9709 } 9710 } 9711 } 9712 PetscFunctionReturn(PETSC_SUCCESS); 9713 } 9714 9715 /*@ 9716 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9717 9718 Collective 9719 9720 Input Parameter: 9721 . dm - The `DMPLEX` object 9722 9723 Level: developer 9724 9725 Notes: 9726 This is mainly intended for debugging/testing purposes. 9727 9728 Other cell types which are disconnected would be caught by the symmetry and face checks. 9729 9730 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9731 9732 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9733 @*/ 9734 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9735 { 9736 PetscInt pStart, pEnd, vStart, vEnd; 9737 9738 PetscFunctionBegin; 9739 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9740 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9741 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9742 for (PetscInt v = vStart; v < vEnd; ++v) { 9743 PetscInt suppSize; 9744 9745 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9746 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9747 } 9748 PetscFunctionReturn(PETSC_SUCCESS); 9749 } 9750 9751 /*@ 9752 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9753 9754 Input Parameter: 9755 . dm - The `DMPLEX` object 9756 9757 Level: developer 9758 9759 Notes: 9760 This is a useful diagnostic when creating meshes programmatically. 9761 9762 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9763 9764 Currently does not include `DMPlexCheckCellShape()`. 9765 9766 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9767 @*/ 9768 PetscErrorCode DMPlexCheck(DM dm) 9769 { 9770 PetscInt cellHeight; 9771 9772 PetscFunctionBegin; 9773 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9774 PetscCall(DMPlexCheckSymmetry(dm)); 9775 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9776 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9777 PetscCall(DMPlexCheckGeometry(dm)); 9778 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9779 PetscCall(DMPlexCheckInterfaceCones(dm)); 9780 PetscCall(DMPlexCheckOrphanVertices(dm)); 9781 PetscFunctionReturn(PETSC_SUCCESS); 9782 } 9783 9784 typedef struct cell_stats { 9785 PetscReal min, max, sum, squaresum; 9786 PetscInt count; 9787 } cell_stats_t; 9788 9789 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9790 { 9791 PetscInt i, N = *len; 9792 9793 for (i = 0; i < N; i++) { 9794 cell_stats_t *A = (cell_stats_t *)a; 9795 cell_stats_t *B = (cell_stats_t *)b; 9796 9797 B->min = PetscMin(A->min, B->min); 9798 B->max = PetscMax(A->max, B->max); 9799 B->sum += A->sum; 9800 B->squaresum += A->squaresum; 9801 B->count += A->count; 9802 } 9803 } 9804 9805 /*@ 9806 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9807 9808 Collective 9809 9810 Input Parameters: 9811 + dm - The `DMPLEX` object 9812 . output - If true, statistics will be displayed on `stdout` 9813 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9814 9815 Level: developer 9816 9817 Notes: 9818 This is mainly intended for debugging/testing purposes. 9819 9820 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9821 9822 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9823 @*/ 9824 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9825 { 9826 DM dmCoarse; 9827 cell_stats_t stats, globalStats; 9828 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9829 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9830 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9831 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9832 PetscMPIInt rank, size; 9833 9834 PetscFunctionBegin; 9835 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9836 stats.min = PETSC_MAX_REAL; 9837 stats.max = PETSC_MIN_REAL; 9838 stats.sum = stats.squaresum = 0.; 9839 stats.count = 0; 9840 9841 PetscCallMPI(MPI_Comm_size(comm, &size)); 9842 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9843 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9844 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9845 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9846 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9847 for (c = cStart; c < cEnd; c++) { 9848 PetscInt i; 9849 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9850 9851 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9852 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9853 for (i = 0; i < PetscSqr(cdim); ++i) { 9854 frobJ += J[i] * J[i]; 9855 frobInvJ += invJ[i] * invJ[i]; 9856 } 9857 cond2 = frobJ * frobInvJ; 9858 cond = PetscSqrtReal(cond2); 9859 9860 stats.min = PetscMin(stats.min, cond); 9861 stats.max = PetscMax(stats.max, cond); 9862 stats.sum += cond; 9863 stats.squaresum += cond2; 9864 stats.count++; 9865 if (output && cond > limit) { 9866 PetscSection coordSection; 9867 Vec coordsLocal; 9868 PetscScalar *coords = NULL; 9869 PetscInt Nv, d, clSize, cl, *closure = NULL; 9870 9871 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9872 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9873 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9874 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9875 for (i = 0; i < Nv / cdim; ++i) { 9876 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9877 for (d = 0; d < cdim; ++d) { 9878 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9879 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9880 } 9881 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9882 } 9883 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9884 for (cl = 0; cl < clSize * 2; cl += 2) { 9885 const PetscInt edge = closure[cl]; 9886 9887 if ((edge >= eStart) && (edge < eEnd)) { 9888 PetscReal len; 9889 9890 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9891 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9892 } 9893 } 9894 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9895 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9896 } 9897 } 9898 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9899 9900 if (size > 1) { 9901 PetscMPIInt blockLengths[2] = {4, 1}; 9902 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9903 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9904 MPI_Op statReduce; 9905 9906 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9907 PetscCallMPI(MPI_Type_commit(&statType)); 9908 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9909 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9910 PetscCallMPI(MPI_Op_free(&statReduce)); 9911 PetscCallMPI(MPI_Type_free(&statType)); 9912 } else { 9913 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9914 } 9915 if (rank == 0) { 9916 count = globalStats.count; 9917 min = globalStats.min; 9918 max = globalStats.max; 9919 mean = globalStats.sum / globalStats.count; 9920 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9921 } 9922 9923 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)); 9924 PetscCall(PetscFree2(J, invJ)); 9925 9926 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9927 if (dmCoarse) { 9928 PetscBool isplex; 9929 9930 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9931 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9932 } 9933 PetscFunctionReturn(PETSC_SUCCESS); 9934 } 9935 9936 /*@ 9937 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9938 orthogonal quality below given tolerance. 9939 9940 Collective 9941 9942 Input Parameters: 9943 + dm - The `DMPLEX` object 9944 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9945 - atol - [0, 1] Absolute tolerance for tagging cells. 9946 9947 Output Parameters: 9948 + OrthQual - `Vec` containing orthogonal quality per cell 9949 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9950 9951 Options Database Keys: 9952 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9953 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9954 9955 Level: intermediate 9956 9957 Notes: 9958 Orthogonal quality is given by the following formula\: 9959 9960 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9961 9962 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 9963 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9964 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9965 calculating the cosine of the angle between these vectors. 9966 9967 Orthogonal quality ranges from 1 (best) to 0 (worst). 9968 9969 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9970 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9971 9972 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9973 9974 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9975 @*/ 9976 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9977 { 9978 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9979 PetscInt *idx; 9980 PetscScalar *oqVals; 9981 const PetscScalar *cellGeomArr, *faceGeomArr; 9982 PetscReal *ci, *fi, *Ai; 9983 MPI_Comm comm; 9984 Vec cellgeom, facegeom; 9985 DM dmFace, dmCell; 9986 IS glob; 9987 ISLocalToGlobalMapping ltog; 9988 PetscViewer vwr; 9989 9990 PetscFunctionBegin; 9991 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9992 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9993 PetscAssertPointer(OrthQual, 4); 9994 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9995 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9996 PetscCall(DMGetDimension(dm, &nc)); 9997 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9998 { 9999 DMPlexInterpolatedFlag interpFlag; 10000 10001 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 10002 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 10003 PetscMPIInt rank; 10004 10005 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 10006 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 10007 } 10008 } 10009 if (OrthQualLabel) { 10010 PetscAssertPointer(OrthQualLabel, 5); 10011 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 10012 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 10013 } else { 10014 *OrthQualLabel = NULL; 10015 } 10016 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 10017 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 10018 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 10019 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 10020 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 10021 PetscCall(VecCreate(comm, OrthQual)); 10022 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 10023 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 10024 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 10025 PetscCall(VecSetUp(*OrthQual)); 10026 PetscCall(ISDestroy(&glob)); 10027 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 10028 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 10029 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 10030 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 10031 PetscCall(VecGetDM(cellgeom, &dmCell)); 10032 PetscCall(VecGetDM(facegeom, &dmFace)); 10033 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 10034 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 10035 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 10036 PetscInt cellarr[2], *adj = NULL; 10037 PetscScalar *cArr, *fArr; 10038 PetscReal minvalc = 1.0, minvalf = 1.0; 10039 PetscFVCellGeom *cg; 10040 10041 idx[cellIter] = cell - cStart; 10042 cellarr[0] = cell; 10043 /* Make indexing into cellGeom easier */ 10044 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10045 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10046 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10047 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10048 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10049 PetscInt i; 10050 const PetscInt neigh = adj[cellneigh]; 10051 PetscReal normci = 0, normfi = 0, normai = 0; 10052 PetscFVCellGeom *cgneigh; 10053 PetscFVFaceGeom *fg; 10054 10055 /* Don't count ourselves in the neighbor list */ 10056 if (neigh == cell) continue; 10057 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10058 cellarr[1] = neigh; 10059 { 10060 PetscInt numcovpts; 10061 const PetscInt *covpts; 10062 10063 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10064 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10065 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10066 } 10067 10068 /* Compute c_i, f_i and their norms */ 10069 for (i = 0; i < nc; i++) { 10070 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10071 fi[i] = fg->centroid[i] - cg->centroid[i]; 10072 Ai[i] = fg->normal[i]; 10073 normci += PetscPowReal(ci[i], 2); 10074 normfi += PetscPowReal(fi[i], 2); 10075 normai += PetscPowReal(Ai[i], 2); 10076 } 10077 normci = PetscSqrtReal(normci); 10078 normfi = PetscSqrtReal(normfi); 10079 normai = PetscSqrtReal(normai); 10080 10081 /* Normalize and compute for each face-cell-normal pair */ 10082 for (i = 0; i < nc; i++) { 10083 ci[i] = ci[i] / normci; 10084 fi[i] = fi[i] / normfi; 10085 Ai[i] = Ai[i] / normai; 10086 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10087 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10088 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10089 } 10090 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10091 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10092 } 10093 PetscCall(PetscFree(adj)); 10094 PetscCall(PetscFree2(cArr, fArr)); 10095 /* Defer to cell if they're equal */ 10096 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10097 if (OrthQualLabel) { 10098 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10099 } 10100 } 10101 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10102 PetscCall(VecAssemblyBegin(*OrthQual)); 10103 PetscCall(VecAssemblyEnd(*OrthQual)); 10104 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10105 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10106 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10107 if (OrthQualLabel) { 10108 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10109 } 10110 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10111 PetscCall(PetscViewerDestroy(&vwr)); 10112 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10113 PetscFunctionReturn(PETSC_SUCCESS); 10114 } 10115 10116 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10117 * interpolator construction */ 10118 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10119 { 10120 PetscSection section, newSection, gsection; 10121 PetscSF sf; 10122 PetscBool hasConstraints, ghasConstraints; 10123 10124 PetscFunctionBegin; 10125 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10126 PetscAssertPointer(odm, 2); 10127 PetscCall(DMGetLocalSection(dm, §ion)); 10128 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10129 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10130 if (!ghasConstraints) { 10131 PetscCall(PetscObjectReference((PetscObject)dm)); 10132 *odm = dm; 10133 PetscFunctionReturn(PETSC_SUCCESS); 10134 } 10135 PetscCall(DMClone(dm, odm)); 10136 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10137 PetscCall(DMGetLocalSection(*odm, &newSection)); 10138 PetscCall(DMGetPointSF(*odm, &sf)); 10139 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10140 PetscCall(DMSetGlobalSection(*odm, gsection)); 10141 PetscCall(PetscSectionDestroy(&gsection)); 10142 PetscFunctionReturn(PETSC_SUCCESS); 10143 } 10144 10145 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10146 { 10147 DM dmco, dmfo; 10148 Mat interpo; 10149 Vec rscale; 10150 Vec cglobalo, clocal; 10151 Vec fglobal, fglobalo, flocal; 10152 PetscBool regular; 10153 10154 PetscFunctionBegin; 10155 PetscCall(DMGetFullDM(dmc, &dmco)); 10156 PetscCall(DMGetFullDM(dmf, &dmfo)); 10157 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10158 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10159 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10160 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10161 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10162 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10163 PetscCall(VecSet(cglobalo, 0.)); 10164 PetscCall(VecSet(clocal, 0.)); 10165 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10166 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10167 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10168 PetscCall(VecSet(fglobal, 0.)); 10169 PetscCall(VecSet(fglobalo, 0.)); 10170 PetscCall(VecSet(flocal, 0.)); 10171 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10172 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10173 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10174 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10175 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10176 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10177 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10178 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10179 *shift = fglobal; 10180 PetscCall(VecDestroy(&flocal)); 10181 PetscCall(VecDestroy(&fglobalo)); 10182 PetscCall(VecDestroy(&clocal)); 10183 PetscCall(VecDestroy(&cglobalo)); 10184 PetscCall(VecDestroy(&rscale)); 10185 PetscCall(MatDestroy(&interpo)); 10186 PetscCall(DMDestroy(&dmfo)); 10187 PetscCall(DMDestroy(&dmco)); 10188 PetscFunctionReturn(PETSC_SUCCESS); 10189 } 10190 10191 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10192 { 10193 PetscObject shifto; 10194 Vec shift; 10195 10196 PetscFunctionBegin; 10197 if (!interp) { 10198 Vec rscale; 10199 10200 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10201 PetscCall(VecDestroy(&rscale)); 10202 } else { 10203 PetscCall(PetscObjectReference((PetscObject)interp)); 10204 } 10205 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10206 if (!shifto) { 10207 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10208 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10209 shifto = (PetscObject)shift; 10210 PetscCall(VecDestroy(&shift)); 10211 } 10212 shift = (Vec)shifto; 10213 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10214 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10215 PetscCall(MatDestroy(&interp)); 10216 PetscFunctionReturn(PETSC_SUCCESS); 10217 } 10218 10219 /* Pointwise interpolation 10220 Just code FEM for now 10221 u^f = I u^c 10222 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10223 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10224 I_{ij} = psi^f_i phi^c_j 10225 */ 10226 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10227 { 10228 PetscSection gsc, gsf; 10229 PetscInt m, n; 10230 void *ctx; 10231 DM cdm; 10232 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10233 10234 PetscFunctionBegin; 10235 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10236 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10237 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10238 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10239 10240 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10241 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10242 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10243 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10244 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10245 10246 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10247 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10248 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10249 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10250 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10251 if (scaling) { 10252 /* Use naive scaling */ 10253 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10254 } 10255 PetscFunctionReturn(PETSC_SUCCESS); 10256 } 10257 10258 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10259 { 10260 VecScatter ctx; 10261 10262 PetscFunctionBegin; 10263 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10264 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10265 PetscCall(VecScatterDestroy(&ctx)); 10266 PetscFunctionReturn(PETSC_SUCCESS); 10267 } 10268 10269 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[]) 10270 { 10271 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10272 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10273 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10274 } 10275 10276 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10277 { 10278 DM dmc; 10279 PetscDS ds; 10280 Vec ones, locmass; 10281 IS cellIS; 10282 PetscFormKey key; 10283 PetscInt depth; 10284 10285 PetscFunctionBegin; 10286 PetscCall(DMClone(dm, &dmc)); 10287 PetscCall(DMCopyDisc(dm, dmc)); 10288 PetscCall(DMGetDS(dmc, &ds)); 10289 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10290 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10291 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10292 else PetscCall(DMGetLocalVector(dm, &locmass)); 10293 PetscCall(DMGetLocalVector(dm, &ones)); 10294 PetscCall(DMPlexGetDepth(dm, &depth)); 10295 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10296 PetscCall(VecSet(locmass, 0.0)); 10297 PetscCall(VecSet(ones, 1.0)); 10298 key.label = NULL; 10299 key.value = 0; 10300 key.field = 0; 10301 key.part = 0; 10302 PetscCall(DMPlexComputeJacobianActionByKey(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10303 PetscCall(ISDestroy(&cellIS)); 10304 if (mass) { 10305 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10306 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10307 } 10308 PetscCall(DMRestoreLocalVector(dm, &ones)); 10309 if (lmass) *lmass = locmass; 10310 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10311 PetscCall(DMDestroy(&dmc)); 10312 PetscFunctionReturn(PETSC_SUCCESS); 10313 } 10314 10315 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10316 { 10317 PetscSection gsc, gsf; 10318 PetscInt m, n; 10319 void *ctx; 10320 DM cdm; 10321 PetscBool regular; 10322 10323 PetscFunctionBegin; 10324 if (dmFine == dmCoarse) { 10325 DM dmc; 10326 PetscDS ds; 10327 PetscWeakForm wf; 10328 Vec u; 10329 IS cellIS; 10330 PetscFormKey key; 10331 PetscInt depth; 10332 10333 PetscCall(DMClone(dmFine, &dmc)); 10334 PetscCall(DMCopyDisc(dmFine, dmc)); 10335 PetscCall(DMGetDS(dmc, &ds)); 10336 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10337 PetscCall(PetscWeakFormClear(wf)); 10338 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10339 PetscCall(DMCreateMatrix(dmc, mass)); 10340 PetscCall(DMGetLocalVector(dmc, &u)); 10341 PetscCall(DMPlexGetDepth(dmc, &depth)); 10342 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10343 PetscCall(MatZeroEntries(*mass)); 10344 key.label = NULL; 10345 key.value = 0; 10346 key.field = 0; 10347 key.part = 0; 10348 PetscCall(DMPlexComputeJacobianByKey(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10349 PetscCall(ISDestroy(&cellIS)); 10350 PetscCall(DMRestoreLocalVector(dmc, &u)); 10351 PetscCall(DMDestroy(&dmc)); 10352 } else { 10353 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10354 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10355 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10356 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10357 10358 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10359 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10360 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10361 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10362 10363 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10364 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10365 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10366 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10367 } 10368 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10369 PetscFunctionReturn(PETSC_SUCCESS); 10370 } 10371 10372 /*@ 10373 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10374 10375 Input Parameter: 10376 . dm - The `DMPLEX` object 10377 10378 Output Parameter: 10379 . regular - The flag 10380 10381 Level: intermediate 10382 10383 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10384 @*/ 10385 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10386 { 10387 PetscFunctionBegin; 10388 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10389 PetscAssertPointer(regular, 2); 10390 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10391 PetscFunctionReturn(PETSC_SUCCESS); 10392 } 10393 10394 /*@ 10395 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10396 10397 Input Parameters: 10398 + dm - The `DMPLEX` object 10399 - regular - The flag 10400 10401 Level: intermediate 10402 10403 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10404 @*/ 10405 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10406 { 10407 PetscFunctionBegin; 10408 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10409 ((DM_Plex *)dm->data)->regularRefinement = regular; 10410 PetscFunctionReturn(PETSC_SUCCESS); 10411 } 10412 10413 /*@ 10414 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10415 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10416 10417 Not Collective 10418 10419 Input Parameter: 10420 . dm - The `DMPLEX` object 10421 10422 Output Parameters: 10423 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10424 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10425 10426 Level: intermediate 10427 10428 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10429 @*/ 10430 PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS) 10431 { 10432 DM_Plex *plex = (DM_Plex *)dm->data; 10433 10434 PetscFunctionBegin; 10435 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10436 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10437 if (anchorSection) *anchorSection = plex->anchorSection; 10438 if (anchorIS) *anchorIS = plex->anchorIS; 10439 PetscFunctionReturn(PETSC_SUCCESS); 10440 } 10441 10442 /*@ 10443 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10444 10445 Collective 10446 10447 Input Parameters: 10448 + dm - The `DMPLEX` object 10449 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10450 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10451 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10452 10453 Level: intermediate 10454 10455 Notes: 10456 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10457 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10458 combination of other points' degrees of freedom. 10459 10460 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10461 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10462 10463 The reference counts of `anchorSection` and `anchorIS` are incremented. 10464 10465 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10466 @*/ 10467 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10468 { 10469 DM_Plex *plex = (DM_Plex *)dm->data; 10470 PetscMPIInt result; 10471 10472 PetscFunctionBegin; 10473 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10474 if (anchorSection) { 10475 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10476 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10477 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10478 } 10479 if (anchorIS) { 10480 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10481 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10482 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10483 } 10484 10485 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10486 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10487 plex->anchorSection = anchorSection; 10488 10489 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10490 PetscCall(ISDestroy(&plex->anchorIS)); 10491 plex->anchorIS = anchorIS; 10492 10493 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10494 PetscInt size, a, pStart, pEnd; 10495 const PetscInt *anchors; 10496 10497 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10498 PetscCall(ISGetLocalSize(anchorIS, &size)); 10499 PetscCall(ISGetIndices(anchorIS, &anchors)); 10500 for (a = 0; a < size; a++) { 10501 PetscInt p; 10502 10503 p = anchors[a]; 10504 if (p >= pStart && p < pEnd) { 10505 PetscInt dof; 10506 10507 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10508 if (dof) { 10509 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10510 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10511 } 10512 } 10513 } 10514 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10515 } 10516 /* reset the generic constraints */ 10517 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10518 PetscFunctionReturn(PETSC_SUCCESS); 10519 } 10520 10521 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10522 { 10523 PetscSection anchorSection; 10524 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10525 10526 PetscFunctionBegin; 10527 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10528 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10529 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10530 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10531 if (numFields) { 10532 PetscInt f; 10533 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10534 10535 for (f = 0; f < numFields; f++) { 10536 PetscInt numComp; 10537 10538 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10539 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10540 } 10541 } 10542 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10543 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10544 pStart = PetscMax(pStart, sStart); 10545 pEnd = PetscMin(pEnd, sEnd); 10546 pEnd = PetscMax(pStart, pEnd); 10547 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10548 for (p = pStart; p < pEnd; p++) { 10549 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10550 if (dof) { 10551 PetscCall(PetscSectionGetDof(section, p, &dof)); 10552 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10553 for (f = 0; f < numFields; f++) { 10554 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10555 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10556 } 10557 } 10558 } 10559 PetscCall(PetscSectionSetUp(*cSec)); 10560 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10561 PetscFunctionReturn(PETSC_SUCCESS); 10562 } 10563 10564 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10565 { 10566 PetscSection aSec; 10567 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10568 const PetscInt *anchors; 10569 PetscInt numFields, f; 10570 IS aIS; 10571 MatType mtype; 10572 PetscBool iscuda, iskokkos; 10573 10574 PetscFunctionBegin; 10575 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10576 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10577 PetscCall(PetscSectionGetStorageSize(section, &n)); 10578 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10579 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10580 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10581 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10582 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10583 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10584 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10585 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10586 else mtype = MATSEQAIJ; 10587 PetscCall(MatSetType(*cMat, mtype)); 10588 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10589 PetscCall(ISGetIndices(aIS, &anchors)); 10590 /* cSec will be a subset of aSec and section */ 10591 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10592 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10593 PetscCall(PetscMalloc1(m + 1, &i)); 10594 i[0] = 0; 10595 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10596 for (p = pStart; p < pEnd; p++) { 10597 PetscInt rDof, rOff, r; 10598 10599 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10600 if (!rDof) continue; 10601 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10602 if (numFields) { 10603 for (f = 0; f < numFields; f++) { 10604 annz = 0; 10605 for (r = 0; r < rDof; r++) { 10606 a = anchors[rOff + r]; 10607 if (a < sStart || a >= sEnd) continue; 10608 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10609 annz += aDof; 10610 } 10611 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10612 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10613 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10614 } 10615 } else { 10616 annz = 0; 10617 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10618 for (q = 0; q < dof; q++) { 10619 a = anchors[rOff + q]; 10620 if (a < sStart || a >= sEnd) continue; 10621 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10622 annz += aDof; 10623 } 10624 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10625 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10626 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10627 } 10628 } 10629 nnz = i[m]; 10630 PetscCall(PetscMalloc1(nnz, &j)); 10631 offset = 0; 10632 for (p = pStart; p < pEnd; p++) { 10633 if (numFields) { 10634 for (f = 0; f < numFields; f++) { 10635 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10636 for (q = 0; q < dof; q++) { 10637 PetscInt rDof, rOff, r; 10638 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10639 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10640 for (r = 0; r < rDof; r++) { 10641 PetscInt s; 10642 10643 a = anchors[rOff + r]; 10644 if (a < sStart || a >= sEnd) continue; 10645 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10646 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10647 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10648 } 10649 } 10650 } 10651 } else { 10652 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10653 for (q = 0; q < dof; q++) { 10654 PetscInt rDof, rOff, r; 10655 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10656 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10657 for (r = 0; r < rDof; r++) { 10658 PetscInt s; 10659 10660 a = anchors[rOff + r]; 10661 if (a < sStart || a >= sEnd) continue; 10662 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10663 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10664 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10665 } 10666 } 10667 } 10668 } 10669 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10670 PetscCall(PetscFree(i)); 10671 PetscCall(PetscFree(j)); 10672 PetscCall(ISRestoreIndices(aIS, &anchors)); 10673 PetscFunctionReturn(PETSC_SUCCESS); 10674 } 10675 10676 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10677 { 10678 DM_Plex *plex = (DM_Plex *)dm->data; 10679 PetscSection anchorSection, section, cSec; 10680 Mat cMat; 10681 10682 PetscFunctionBegin; 10683 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10684 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10685 if (anchorSection) { 10686 PetscInt Nf; 10687 10688 PetscCall(DMGetLocalSection(dm, §ion)); 10689 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10690 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10691 PetscCall(DMGetNumFields(dm, &Nf)); 10692 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10693 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10694 PetscCall(PetscSectionDestroy(&cSec)); 10695 PetscCall(MatDestroy(&cMat)); 10696 } 10697 PetscFunctionReturn(PETSC_SUCCESS); 10698 } 10699 10700 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10701 { 10702 IS subis; 10703 PetscSection section, subsection; 10704 10705 PetscFunctionBegin; 10706 PetscCall(DMGetLocalSection(dm, §ion)); 10707 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10708 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10709 /* Create subdomain */ 10710 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10711 /* Create submodel */ 10712 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10713 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10714 PetscCall(DMSetLocalSection(*subdm, subsection)); 10715 PetscCall(PetscSectionDestroy(&subsection)); 10716 PetscCall(DMCopyDisc(dm, *subdm)); 10717 /* Create map from submodel to global model */ 10718 if (is) { 10719 PetscSection sectionGlobal, subsectionGlobal; 10720 IS spIS; 10721 const PetscInt *spmap; 10722 PetscInt *subIndices; 10723 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10724 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10725 10726 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10727 PetscCall(ISGetIndices(spIS, &spmap)); 10728 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10729 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10730 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10731 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10732 for (p = pStart; p < pEnd; ++p) { 10733 PetscInt gdof, pSubSize = 0; 10734 10735 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10736 if (gdof > 0) { 10737 for (f = 0; f < Nf; ++f) { 10738 PetscInt fdof, fcdof; 10739 10740 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10741 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10742 pSubSize += fdof - fcdof; 10743 } 10744 subSize += pSubSize; 10745 if (pSubSize) { 10746 if (bs < 0) { 10747 bs = pSubSize; 10748 } else if (bs != pSubSize) { 10749 /* Layout does not admit a pointwise block size */ 10750 bs = 1; 10751 } 10752 } 10753 } 10754 } 10755 /* Must have same blocksize on all procs (some might have no points) */ 10756 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10757 bsLocal[1] = bs; 10758 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10759 if (bsMinMax[0] != bsMinMax[1]) { 10760 bs = 1; 10761 } else { 10762 bs = bsMinMax[0]; 10763 } 10764 PetscCall(PetscMalloc1(subSize, &subIndices)); 10765 for (p = pStart; p < pEnd; ++p) { 10766 PetscInt gdof, goff; 10767 10768 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10769 if (gdof > 0) { 10770 const PetscInt point = spmap[p]; 10771 10772 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10773 for (f = 0; f < Nf; ++f) { 10774 PetscInt fdof, fcdof, fc, f2, poff = 0; 10775 10776 /* Can get rid of this loop by storing field information in the global section */ 10777 for (f2 = 0; f2 < f; ++f2) { 10778 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10779 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10780 poff += fdof - fcdof; 10781 } 10782 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10783 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10784 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10785 } 10786 } 10787 } 10788 PetscCall(ISRestoreIndices(spIS, &spmap)); 10789 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10790 if (bs > 1) { 10791 /* We need to check that the block size does not come from non-contiguous fields */ 10792 PetscInt i, j, set = 1; 10793 for (i = 0; i < subSize; i += bs) { 10794 for (j = 0; j < bs; ++j) { 10795 if (subIndices[i + j] != subIndices[i] + j) { 10796 set = 0; 10797 break; 10798 } 10799 } 10800 } 10801 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10802 } 10803 // Attach nullspace 10804 if (dm->nullspaceConstructors) { 10805 for (f = 0; f < Nf; ++f) { 10806 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10807 if ((*subdm)->nullspaceConstructors[f]) break; 10808 } 10809 if (f < Nf) { 10810 MatNullSpace nullSpace; 10811 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10812 10813 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10814 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10815 } 10816 } 10817 } 10818 PetscFunctionReturn(PETSC_SUCCESS); 10819 } 10820 10821 /*@ 10822 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10823 10824 Input Parameters: 10825 + dm - The `DM` 10826 - dummy - unused argument 10827 10828 Options Database Key: 10829 . -dm_plex_monitor_throughput - Activate the monitor 10830 10831 Level: developer 10832 10833 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10834 @*/ 10835 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10836 { 10837 PetscLogHandler default_handler; 10838 10839 PetscFunctionBegin; 10840 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10841 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10842 if (default_handler) { 10843 PetscLogEvent event; 10844 PetscEventPerfInfo eventInfo; 10845 PetscLogDouble cellRate, flopRate; 10846 PetscInt cStart, cEnd, Nf, N; 10847 const char *name; 10848 10849 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10850 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10851 PetscCall(DMGetNumFields(dm, &Nf)); 10852 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10853 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10854 N = (cEnd - cStart) * Nf * eventInfo.count; 10855 flopRate = eventInfo.flops / eventInfo.time; 10856 cellRate = N / eventInfo.time; 10857 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)); 10858 } else { 10859 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."); 10860 } 10861 PetscFunctionReturn(PETSC_SUCCESS); 10862 } 10863