1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_CreateBoxSFC, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 /* Logging support */ 18 PetscLogEvent DMPLEX_DistributionView, DMPLEX_DistributionLoad; 19 20 PetscBool Plexcite = PETSC_FALSE; 21 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 22 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 23 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 24 "journal = {SIAM Journal on Scientific Computing},\n" 25 "volume = {38},\n" 26 "number = {5},\n" 27 "pages = {S143--S155},\n" 28 "eprint = {http://arxiv.org/abs/1506.07749},\n" 29 "doi = {10.1137/15M1026092},\n" 30 "year = {2016},\n" 31 "petsc_uses={DMPlex},\n}\n"; 32 33 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 34 35 /*@ 36 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 37 38 Input Parameter: 39 . dm - The `DMPLEX` object 40 41 Output Parameter: 42 . simplex - Flag checking for a simplex 43 44 Level: intermediate 45 46 Note: 47 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 48 If the mesh has no cells, this returns `PETSC_FALSE`. 49 50 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 51 @*/ 52 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 53 { 54 DMPolytopeType ct; 55 PetscInt cStart, cEnd; 56 57 PetscFunctionBegin; 58 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 59 if (cEnd <= cStart) { 60 *simplex = PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 64 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 65 PetscFunctionReturn(PETSC_SUCCESS); 66 } 67 68 /*@ 69 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 70 71 Input Parameters: 72 + dm - The `DMPLEX` object 73 - height - The cell height in the Plex, 0 is the default 74 75 Output Parameters: 76 + cStart - The first "normal" cell, pass `NULL` if not needed 77 - cEnd - The upper bound on "normal" cells, pass `NULL` if not needed 78 79 Level: developer 80 81 Note: 82 This function requires that tensor cells are ordered last. 83 84 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 85 @*/ 86 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PeOp PetscInt *cStart, PeOp PetscInt *cEnd) 87 { 88 DMLabel ctLabel; 89 IS valueIS; 90 const PetscInt *ctypes; 91 PetscBool found = PETSC_FALSE; 92 PetscInt Nct, cS = PETSC_INT_MAX, cE = 0; 93 94 PetscFunctionBegin; 95 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 96 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 97 PetscCall(ISGetLocalSize(valueIS, &Nct)); 98 PetscCall(ISGetIndices(valueIS, &ctypes)); 99 for (PetscInt t = 0; t < Nct; ++t) { 100 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 101 PetscInt ctS, ctE, ht; 102 103 if (ct == DM_POLYTOPE_UNKNOWN) { 104 // If any cells are not typed, just use all cells 105 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 106 break; 107 } 108 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 109 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 110 if (ctS >= ctE) continue; 111 // Check that a point has the right height 112 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 113 if (ht != height) continue; 114 cS = PetscMin(cS, ctS); 115 cE = PetscMax(cE, ctE); 116 found = PETSC_TRUE; 117 } 118 if (!Nct || !found) cS = cE = 0; 119 PetscCall(ISDestroy(&valueIS)); 120 // Reset label for fast lookup 121 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 122 if (cStart) *cStart = cS; 123 if (cEnd) *cEnd = cE; 124 PetscFunctionReturn(PETSC_SUCCESS); 125 } 126 127 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 128 { 129 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 130 PetscInt *sStart, *sEnd; 131 PetscViewerVTKFieldType *ft; 132 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 133 DMLabel depthLabel, ctLabel; 134 135 PetscFunctionBegin; 136 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 137 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 138 PetscCall(DMGetCoordinateDim(dm, &cdim)); 139 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 140 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 141 if (field >= 0) { 142 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 143 } else { 144 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 145 } 146 147 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 148 PetscCall(DMPlexGetDepth(dm, &depth)); 149 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 150 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 151 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 152 const DMPolytopeType ict = (DMPolytopeType)c; 153 PetscInt dep; 154 155 if (ict == DM_POLYTOPE_FV_GHOST) continue; 156 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 157 if (pStart >= 0) { 158 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 159 if (dep != depth - cellHeight) continue; 160 } 161 if (field >= 0) { 162 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 163 } else { 164 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 165 } 166 } 167 168 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 169 *types = 0; 170 171 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 172 if (globalvcdof[c]) ++(*types); 173 } 174 175 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 176 t = 0; 177 if (globalvcdof[DM_NUM_POLYTOPES]) { 178 sStart[t] = vStart; 179 sEnd[t] = vEnd; 180 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 181 ++t; 182 } 183 184 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 185 if (globalvcdof[c]) { 186 const DMPolytopeType ict = (DMPolytopeType)c; 187 188 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 189 sStart[t] = cStart; 190 sEnd[t] = cEnd; 191 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 192 ++t; 193 } 194 } 195 196 if (!*types) { 197 if (field >= 0) { 198 const char *fieldname; 199 200 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 201 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 202 } else { 203 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 204 } 205 } 206 207 *ssStart = sStart; 208 *ssEnd = sEnd; 209 *sft = ft; 210 PetscFunctionReturn(PETSC_SUCCESS); 211 } 212 213 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 214 { 215 PetscFunctionBegin; 216 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 217 PetscFunctionReturn(PETSC_SUCCESS); 218 } 219 220 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 221 { 222 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 223 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 224 225 PetscFunctionBegin; 226 *ft = PETSC_VTK_INVALID; 227 PetscCall(DMGetCoordinateDim(dm, &cdim)); 228 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 229 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 230 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 231 if (field >= 0) { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 234 } else { 235 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 236 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 237 } 238 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 239 if (globalvcdof[0]) { 240 *sStart = vStart; 241 *sEnd = vEnd; 242 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 243 else *ft = PETSC_VTK_POINT_FIELD; 244 } else if (globalvcdof[1]) { 245 *sStart = cStart; 246 *sEnd = cEnd; 247 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 248 else *ft = PETSC_VTK_CELL_FIELD; 249 } else { 250 if (field >= 0) { 251 const char *fieldname; 252 253 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 254 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 255 } else { 256 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n")); 257 } 258 } 259 PetscFunctionReturn(PETSC_SUCCESS); 260 } 261 262 /*@ 263 DMPlexVecView1D - Plot many 1D solutions on the same line graph 264 265 Collective 266 267 Input Parameters: 268 + dm - The `DMPLEX` object 269 . n - The number of vectors 270 . u - The array of local vectors 271 - viewer - The `PetscViewer` 272 273 Level: advanced 274 275 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 276 @*/ 277 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 278 { 279 DM cdm; 280 PetscDS ds; 281 PetscDraw draw = NULL; 282 PetscDrawLG lg; 283 Vec coordinates; 284 const PetscScalar *coords, **sol; 285 PetscReal *vals; 286 PetscInt *Nc; 287 PetscInt Nf, Nl, vStart, vEnd, eStart, eEnd; 288 char **names; 289 290 PetscFunctionBegin; 291 PetscCall(DMGetCoordinateDM(dm, &cdm)); 292 PetscCall(DMGetDS(dm, &ds)); 293 PetscCall(PetscDSGetNumFields(ds, &Nf)); 294 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 295 PetscCall(PetscDSGetComponents(ds, &Nc)); 296 297 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 298 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 299 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 300 301 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 302 for (PetscInt i = 0, l = 0; i < n; ++i) { 303 const char *vname; 304 305 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 306 for (PetscInt f = 0; f < Nf; ++f) { 307 PetscObject disc; 308 const char *fname; 309 char tmpname[PETSC_MAX_PATH_LEN]; 310 311 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 312 /* TODO Create names for components */ 313 for (PetscInt c = 0; c < Nc[f]; ++c, ++l) { 314 PetscCall(PetscObjectGetName(disc, &fname)); 315 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 316 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 317 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 318 PetscCall(PetscStrallocpy(tmpname, &names[l])); 319 } 320 } 321 } 322 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 323 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 324 PetscCall(VecGetArrayRead(coordinates, &coords)); 325 for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 326 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 327 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 328 PetscSection s; 329 PetscInt cdof, vdof; 330 331 PetscCall(DMGetLocalSection(dm, &s)); 332 PetscCall(PetscSectionGetDof(s, eStart, &cdof)); 333 PetscCall(PetscSectionGetDof(s, vStart, &vdof)); 334 if (cdof) { 335 if (vdof) { 336 // P_2 337 PetscInt vFirst = -1; 338 339 for (PetscInt e = eStart; e < eEnd; ++e) { 340 PetscScalar *xa, *xb, *svals; 341 const PetscInt *cone; 342 343 PetscCall(DMPlexGetCone(dm, e, &cone)); 344 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 345 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 346 if (e == eStart) vFirst = cone[0]; 347 for (PetscInt i = 0; i < n; ++i) { 348 PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals)); 349 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 350 } 351 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals)); 352 if (e == eEnd - 1 && cone[1] != vFirst) { 353 for (PetscInt i = 0; i < n; ++i) { 354 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 355 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 356 } 357 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 358 for (PetscInt i = 0; i < n; ++i) { 359 PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals)); 360 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 361 } 362 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals)); 363 } 364 } 365 } else { 366 // P_0 367 for (PetscInt e = eStart; e < eEnd; ++e) { 368 PetscScalar *xa, *xb, *svals; 369 const PetscInt *cone; 370 371 PetscCall(DMPlexGetCone(dm, e, &cone)); 372 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 373 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 374 for (PetscInt i = 0; i < n; ++i) { 375 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 376 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 377 } 378 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 379 } 380 } 381 } else if (vdof) { 382 // P_1 383 for (PetscInt v = vStart; v < vEnd; ++v) { 384 PetscScalar *x, *svals; 385 386 PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x)); 387 for (PetscInt i = 0; i < n; ++i) { 388 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 389 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 390 } 391 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 392 } 393 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Discretization not supported"); 394 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 395 for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 396 for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 397 PetscCall(PetscFree3(sol, names, vals)); 398 399 PetscCall(PetscDrawLGDraw(lg)); 400 PetscCall(PetscDrawLGDestroy(&lg)); 401 PetscFunctionReturn(PETSC_SUCCESS); 402 } 403 404 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 405 { 406 DM dm; 407 408 PetscFunctionBegin; 409 PetscCall(VecGetDM(u, &dm)); 410 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 411 PetscFunctionReturn(PETSC_SUCCESS); 412 } 413 414 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 415 { 416 DM dm; 417 PetscSection s; 418 PetscDraw draw, popup; 419 DM cdm; 420 PetscSection coordSection; 421 Vec coordinates; 422 const PetscScalar *array; 423 PetscReal lbound[3], ubound[3]; 424 PetscReal vbound[2], time; 425 PetscBool flg; 426 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 427 const char *name; 428 char title[PETSC_MAX_PATH_LEN]; 429 430 PetscFunctionBegin; 431 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 432 PetscCall(VecGetDM(v, &dm)); 433 PetscCall(DMGetCoordinateDim(dm, &dim)); 434 PetscCall(DMGetLocalSection(dm, &s)); 435 PetscCall(PetscSectionGetNumFields(s, &Nf)); 436 PetscCall(DMGetCoarsenLevel(dm, &level)); 437 PetscCall(DMGetCoordinateDM(dm, &cdm)); 438 PetscCall(DMGetLocalSection(cdm, &coordSection)); 439 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 440 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 441 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 442 443 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 444 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 445 446 PetscCall(VecGetLocalSize(coordinates, &N)); 447 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 448 PetscCall(PetscDrawClear(draw)); 449 450 /* Could implement something like DMDASelectFields() */ 451 for (f = 0; f < Nf; ++f) { 452 DM fdm = dm; 453 Vec fv = v; 454 IS fis; 455 char prefix[PETSC_MAX_PATH_LEN]; 456 const char *fname; 457 458 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 459 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 460 461 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 462 else prefix[0] = '\0'; 463 if (Nf > 1) { 464 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 465 PetscCall(VecGetSubVector(v, fis, &fv)); 466 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 467 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 468 } 469 for (comp = 0; comp < Nc; ++comp, ++w) { 470 PetscInt nmax = 2; 471 472 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 473 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 474 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 475 PetscCall(PetscDrawSetTitle(draw, title)); 476 477 /* TODO Get max and min only for this component */ 478 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 479 if (!flg) { 480 PetscCall(VecMin(fv, NULL, &vbound[0])); 481 PetscCall(VecMax(fv, NULL, &vbound[1])); 482 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 483 } 484 485 PetscCall(PetscDrawGetPopup(draw, &popup)); 486 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 487 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 488 PetscCall(VecGetArrayRead(fv, &array)); 489 for (c = cStart; c < cEnd; ++c) { 490 DMPolytopeType ct; 491 PetscScalar *coords = NULL, *a = NULL; 492 const PetscScalar *coords_arr; 493 PetscBool isDG; 494 PetscInt numCoords; 495 int color[4] = {-1, -1, -1, -1}; 496 497 PetscCall(DMPlexGetCellType(dm, c, &ct)); 498 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 499 if (a) { 500 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 501 color[1] = color[2] = color[3] = color[0]; 502 } else { 503 PetscScalar *vals = NULL; 504 PetscInt numVals, va; 505 506 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 507 if (!numVals) { 508 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 509 continue; 510 } 511 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 512 switch (numVals / Nc) { 513 case 1: /* P1 Clamped Segment Prism */ 514 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 515 PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]); 516 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 517 break; 518 case 3: /* P1 Triangle */ 519 case 4: /* P1 Quadrangle */ 520 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 521 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 522 break; 523 case 6: /* P2 Triangle */ 524 case 8: /* P2 Quadrangle */ 525 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 526 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 527 break; 528 default: 529 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 530 } 531 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 532 } 533 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 534 switch (numCoords) { 535 case 6: 536 case 12: /* Localized triangle */ 537 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 538 break; 539 case 8: 540 case 16: /* Localized quadrilateral */ 541 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 542 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 543 } else { 544 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 545 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 546 } 547 break; 548 default: 549 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 550 } 551 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 552 } 553 PetscCall(VecRestoreArrayRead(fv, &array)); 554 PetscCall(PetscDrawFlush(draw)); 555 PetscCall(PetscDrawPause(draw)); 556 PetscCall(PetscDrawSave(draw)); 557 } 558 if (Nf > 1) { 559 PetscCall(VecRestoreSubVector(v, fis, &fv)); 560 PetscCall(ISDestroy(&fis)); 561 PetscCall(DMDestroy(&fdm)); 562 } 563 } 564 PetscFunctionReturn(PETSC_SUCCESS); 565 } 566 567 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 568 { 569 DM dm; 570 PetscDraw draw; 571 PetscInt dim; 572 PetscBool isnull; 573 574 PetscFunctionBegin; 575 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 576 PetscCall(PetscDrawIsNull(draw, &isnull)); 577 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 578 579 PetscCall(VecGetDM(v, &dm)); 580 PetscCall(DMGetCoordinateDim(dm, &dim)); 581 switch (dim) { 582 case 1: 583 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 584 break; 585 case 2: 586 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 587 break; 588 default: 589 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 590 } 591 PetscFunctionReturn(PETSC_SUCCESS); 592 } 593 594 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 595 { 596 DM dm; 597 Vec locv; 598 const char *name; 599 PetscSection section; 600 PetscInt pStart, pEnd; 601 PetscInt numFields; 602 PetscViewerVTKFieldType ft; 603 604 PetscFunctionBegin; 605 PetscCall(VecGetDM(v, &dm)); 606 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 607 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 608 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 609 PetscCall(VecCopy(v, locv)); 610 PetscCall(DMGetLocalSection(dm, §ion)); 611 PetscCall(PetscSectionGetNumFields(section, &numFields)); 612 if (!numFields) { 613 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 614 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 615 } else { 616 PetscInt f; 617 618 for (f = 0; f < numFields; f++) { 619 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 620 if (ft == PETSC_VTK_INVALID) continue; 621 PetscCall(PetscObjectReference((PetscObject)locv)); 622 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 623 } 624 PetscCall(VecDestroy(&locv)); 625 } 626 PetscFunctionReturn(PETSC_SUCCESS); 627 } 628 629 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 630 { 631 DM dm; 632 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython; 633 634 PetscFunctionBegin; 635 PetscCall(VecGetDM(v, &dm)); 636 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 640 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 641 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 642 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 643 if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) { 644 PetscInt i, numFields; 645 PetscObject fe; 646 PetscBool fem = PETSC_FALSE; 647 Vec locv = v; 648 const char *name; 649 PetscInt step; 650 PetscReal time; 651 652 PetscCall(DMGetNumFields(dm, &numFields)); 653 for (i = 0; i < numFields; i++) { 654 PetscCall(DMGetField(dm, i, NULL, &fe)); 655 if (fe->classid == PETSCFE_CLASSID) { 656 fem = PETSC_TRUE; 657 break; 658 } 659 } 660 if (fem) { 661 PetscObject isZero; 662 663 PetscCall(DMGetLocalVector(dm, &locv)); 664 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 665 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 666 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 667 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 668 PetscCall(VecCopy(v, locv)); 669 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 670 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 671 } 672 if (isvtk) { 673 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 674 } else if (ishdf5) { 675 #if defined(PETSC_HAVE_HDF5) 676 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 677 #else 678 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 679 #endif 680 } else if (isdraw) { 681 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 682 } else if (ispython) { 683 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv)); 684 } else if (isglvis) { 685 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 686 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 687 PetscCall(VecView_GLVis(locv, viewer)); 688 } else if (iscgns) { 689 #if defined(PETSC_HAVE_CGNS) 690 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 691 #else 692 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 693 #endif 694 } 695 if (fem) { 696 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 697 PetscCall(DMRestoreLocalVector(dm, &locv)); 698 } 699 } else { 700 PetscBool isseq; 701 702 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 703 if (isseq) PetscCall(VecView_Seq(v, viewer)); 704 else PetscCall(VecView_MPI(v, viewer)); 705 } 706 PetscFunctionReturn(PETSC_SUCCESS); 707 } 708 709 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 710 { 711 DM dm; 712 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython; 713 714 PetscFunctionBegin; 715 PetscCall(VecGetDM(v, &dm)); 716 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 721 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 722 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 723 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 724 if (isvtk || isdraw || isglvis || iscgns || ispython) { 725 Vec locv; 726 PetscObject isZero; 727 const char *name; 728 729 PetscCall(DMGetLocalVector(dm, &locv)); 730 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 731 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 732 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 733 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 734 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 735 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 736 PetscCall(VecView_Plex_Local(locv, viewer)); 737 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 738 PetscCall(DMRestoreLocalVector(dm, &locv)); 739 } else if (ishdf5) { 740 #if defined(PETSC_HAVE_HDF5) 741 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 742 #else 743 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 744 #endif 745 } else if (isexodusii) { 746 #if defined(PETSC_HAVE_EXODUSII) 747 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 748 #else 749 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 750 #endif 751 } else { 752 PetscBool isseq; 753 754 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 755 if (isseq) PetscCall(VecView_Seq(v, viewer)); 756 else PetscCall(VecView_MPI(v, viewer)); 757 } 758 PetscFunctionReturn(PETSC_SUCCESS); 759 } 760 761 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 762 { 763 DM dm; 764 MPI_Comm comm; 765 PetscViewerFormat format; 766 Vec v; 767 PetscBool isvtk, ishdf5; 768 769 PetscFunctionBegin; 770 PetscCall(VecGetDM(originalv, &dm)); 771 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 772 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 773 PetscCall(PetscViewerGetFormat(viewer, &format)); 774 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 775 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 776 if (format == PETSC_VIEWER_NATIVE) { 777 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 778 /* this need a better fix */ 779 if (dm->useNatural) { 780 if (dm->sfNatural) { 781 const char *vecname; 782 PetscInt n, nroots; 783 784 PetscCall(VecGetLocalSize(originalv, &n)); 785 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 786 if (n == nroots) { 787 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 788 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 789 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 790 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 791 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 792 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 793 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 794 } else v = originalv; 795 } else v = originalv; 796 797 if (ishdf5) { 798 #if defined(PETSC_HAVE_HDF5) 799 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 800 #else 801 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 802 #endif 803 } else if (isvtk) { 804 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 805 } else { 806 PetscBool isseq; 807 808 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 809 if (isseq) PetscCall(VecView_Seq(v, viewer)); 810 else PetscCall(VecView_MPI(v, viewer)); 811 } 812 if (v != originalv) PetscCall(VecDestroy(&v)); 813 PetscFunctionReturn(PETSC_SUCCESS); 814 } 815 816 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 817 { 818 DM dm; 819 PetscBool ishdf5; 820 821 PetscFunctionBegin; 822 PetscCall(VecGetDM(v, &dm)); 823 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 824 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 825 if (ishdf5) { 826 DM dmBC; 827 Vec gv; 828 const char *name; 829 830 PetscCall(DMGetOutputDM(dm, &dmBC)); 831 PetscCall(DMGetGlobalVector(dmBC, &gv)); 832 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 833 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 834 PetscCall(VecLoad_Default(gv, viewer)); 835 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 836 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 837 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 838 } else PetscCall(VecLoad_Default(v, viewer)); 839 PetscFunctionReturn(PETSC_SUCCESS); 840 } 841 842 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 843 { 844 DM dm; 845 PetscBool ishdf5, isexodusii, iscgns; 846 847 PetscFunctionBegin; 848 PetscCall(VecGetDM(v, &dm)); 849 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 850 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 851 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 852 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 853 if (ishdf5) { 854 #if defined(PETSC_HAVE_HDF5) 855 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 856 #else 857 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 858 #endif 859 } else if (isexodusii) { 860 #if defined(PETSC_HAVE_EXODUSII) 861 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 862 #else 863 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 864 #endif 865 } else if (iscgns) { 866 #if defined(PETSC_HAVE_CGNS) 867 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 868 #else 869 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 870 #endif 871 } else PetscCall(VecLoad_Default(v, viewer)); 872 PetscFunctionReturn(PETSC_SUCCESS); 873 } 874 875 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 876 { 877 DM dm; 878 PetscViewerFormat format; 879 PetscBool ishdf5; 880 881 PetscFunctionBegin; 882 PetscCall(VecGetDM(originalv, &dm)); 883 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 884 PetscCall(PetscViewerGetFormat(viewer, &format)); 885 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 886 if (format == PETSC_VIEWER_NATIVE) { 887 if (dm->useNatural) { 888 if (dm->sfNatural) { 889 if (ishdf5) { 890 #if defined(PETSC_HAVE_HDF5) 891 Vec v; 892 const char *vecname; 893 894 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 895 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 896 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 897 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 898 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 899 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 900 PetscCall(VecDestroy(&v)); 901 #else 902 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 903 #endif 904 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 905 } 906 } else PetscCall(VecLoad_Default(originalv, viewer)); 907 } 908 PetscFunctionReturn(PETSC_SUCCESS); 909 } 910 911 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 912 { 913 PetscSection coordSection; 914 Vec coordinates; 915 DMLabel depthLabel, celltypeLabel; 916 const char *name[4]; 917 const PetscScalar *a; 918 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 919 920 PetscFunctionBegin; 921 PetscCall(DMGetDimension(dm, &dim)); 922 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 923 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 924 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 925 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 926 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 927 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 928 PetscCall(VecGetArrayRead(coordinates, &a)); 929 name[0] = "vertex"; 930 name[1] = "edge"; 931 name[dim - 1] = "face"; 932 name[dim] = "cell"; 933 for (c = cStart; c < cEnd; ++c) { 934 PetscInt *closure = NULL; 935 PetscInt closureSize, cl, ct; 936 937 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 938 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 939 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 940 PetscCall(PetscViewerASCIIPushTab(viewer)); 941 for (cl = 0; cl < closureSize * 2; cl += 2) { 942 PetscInt point = closure[cl], depth, dof, off, d, p; 943 944 if ((point < pStart) || (point >= pEnd)) continue; 945 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 946 if (!dof) continue; 947 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 948 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 949 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 950 for (p = 0; p < dof / dim; ++p) { 951 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 952 for (d = 0; d < dim; ++d) { 953 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 955 } 956 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 957 } 958 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 959 } 960 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 961 PetscCall(PetscViewerASCIIPopTab(viewer)); 962 } 963 PetscCall(VecRestoreArrayRead(coordinates, &a)); 964 PetscFunctionReturn(PETSC_SUCCESS); 965 } 966 967 typedef enum { 968 CS_CARTESIAN, 969 CS_POLAR, 970 CS_CYLINDRICAL, 971 CS_SPHERICAL 972 } CoordSystem; 973 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 974 975 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 976 { 977 PetscInt i; 978 979 PetscFunctionBegin; 980 if (dim > 3) { 981 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 982 } else { 983 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 984 985 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 986 switch (cs) { 987 case CS_CARTESIAN: 988 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 989 break; 990 case CS_POLAR: 991 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 992 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 993 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 994 break; 995 case CS_CYLINDRICAL: 996 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 997 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 998 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 999 trcoords[2] = coords[2]; 1000 break; 1001 case CS_SPHERICAL: 1002 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 1003 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 1004 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 1005 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 1006 break; 1007 } 1008 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 1009 } 1010 PetscFunctionReturn(PETSC_SUCCESS); 1011 } 1012 1013 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 1014 { 1015 DM_Plex *mesh = (DM_Plex *)dm->data; 1016 DM cdm, cdmCell; 1017 PetscSection coordSection, coordSectionCell; 1018 Vec coordinates, coordinatesCell; 1019 PetscViewerFormat format; 1020 1021 PetscFunctionBegin; 1022 PetscCall(PetscViewerGetFormat(viewer, &format)); 1023 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1024 const char *name; 1025 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1026 PetscInt pStart, pEnd, p, numLabels, l; 1027 PetscMPIInt rank, size; 1028 1029 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1030 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1031 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1032 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1033 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1034 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1035 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1036 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1037 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1038 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1039 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1040 PetscCall(DMGetDimension(dm, &dim)); 1041 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1042 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1043 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1044 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1045 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1046 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1047 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1048 for (p = pStart; p < pEnd; ++p) { 1049 PetscInt dof, off, s; 1050 1051 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1052 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1053 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1054 } 1055 PetscCall(PetscViewerFlush(viewer)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1057 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1058 for (p = pStart; p < pEnd; ++p) { 1059 PetscInt dof, off, c; 1060 1061 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1062 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1063 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 1064 } 1065 PetscCall(PetscViewerFlush(viewer)); 1066 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1067 if (coordSection && coordinates) { 1068 CoordSystem cs = CS_CARTESIAN; 1069 const PetscScalar *array, *arrayCell = NULL; 1070 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1071 PetscMPIInt rank; 1072 const char *name; 1073 1074 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1075 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1076 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1077 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1078 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1079 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1080 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1081 pStart = PetscMin(pvStart, pcStart); 1082 pEnd = PetscMax(pvEnd, pcEnd); 1083 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1084 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1085 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1086 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1087 1088 PetscCall(VecGetArrayRead(coordinates, &array)); 1089 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1090 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1091 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1092 for (p = pStart; p < pEnd; ++p) { 1093 PetscInt dof, off; 1094 1095 if (p >= pvStart && p < pvEnd) { 1096 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1097 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1098 if (dof) { 1099 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1100 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1101 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1102 } 1103 } 1104 if (cdmCell && p >= pcStart && p < pcEnd) { 1105 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1106 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1107 if (dof) { 1108 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1109 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1110 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1111 } 1112 } 1113 } 1114 PetscCall(PetscViewerFlush(viewer)); 1115 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1116 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1117 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1118 } 1119 PetscCall(DMGetNumLabels(dm, &numLabels)); 1120 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1121 for (l = 0; l < numLabels; ++l) { 1122 DMLabel label; 1123 PetscBool isdepth; 1124 const char *name; 1125 1126 PetscCall(DMGetLabelName(dm, l, &name)); 1127 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1128 if (isdepth) continue; 1129 PetscCall(DMGetLabel(dm, name, &label)); 1130 PetscCall(DMLabelView(label, viewer)); 1131 } 1132 if (size > 1) { 1133 PetscSF sf; 1134 1135 PetscCall(DMGetPointSF(dm, &sf)); 1136 PetscCall(PetscSFView(sf, viewer)); 1137 } 1138 if (mesh->periodic.face_sfs) 1139 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1140 PetscCall(PetscViewerFlush(viewer)); 1141 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1142 const char *name, *color; 1143 const char *defcolors[3] = {"gray", "orange", "green"}; 1144 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1145 char lname[PETSC_MAX_PATH_LEN]; 1146 PetscReal scale = 2.0; 1147 PetscReal tikzscale = 1.0; 1148 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1149 double tcoords[3]; 1150 PetscScalar *coords; 1151 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 1152 PetscMPIInt rank, size; 1153 char **names, **colors, **lcolors; 1154 PetscBool flg, lflg; 1155 PetscBT wp = NULL; 1156 PetscInt pEnd, pStart; 1157 1158 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1159 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1160 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1161 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1162 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1163 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1164 PetscCall(DMGetDimension(dm, &dim)); 1165 PetscCall(DMPlexGetDepth(dm, &depth)); 1166 PetscCall(DMGetNumLabels(dm, &numLabels)); 1167 numLabels = PetscMax(numLabels, 10); 1168 numColors = 10; 1169 numLColors = 10; 1170 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1171 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1172 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1173 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1174 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1175 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1176 n = 4; 1177 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1178 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1179 n = 4; 1180 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1181 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1182 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1183 if (!useLabels) numLabels = 0; 1184 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1185 if (!useColors) { 1186 numColors = 3; 1187 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1188 } 1189 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1190 if (!useColors) { 1191 numLColors = 4; 1192 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1193 } 1194 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1195 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1196 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1197 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1198 if (depth < dim) plotEdges = PETSC_FALSE; 1199 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1200 1201 /* filter points with labelvalue != labeldefaultvalue */ 1202 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1203 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1204 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1205 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1206 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1207 if (lflg) { 1208 DMLabel lbl; 1209 1210 PetscCall(DMGetLabel(dm, lname, &lbl)); 1211 if (lbl) { 1212 PetscInt val, defval; 1213 1214 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1215 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1216 for (c = pStart; c < pEnd; c++) { 1217 PetscInt *closure = NULL; 1218 PetscInt closureSize; 1219 1220 PetscCall(DMLabelGetValue(lbl, c, &val)); 1221 if (val == defval) continue; 1222 1223 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1224 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1225 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1226 } 1227 } 1228 } 1229 1230 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1231 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1232 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1234 \\documentclass[tikz]{standalone}\n\n\ 1235 \\usepackage{pgflibraryshapes}\n\ 1236 \\usetikzlibrary{backgrounds}\n\ 1237 \\usetikzlibrary{arrows}\n\ 1238 \\begin{document}\n")); 1239 if (size > 1) { 1240 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1241 for (p = 0; p < size; ++p) { 1242 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1243 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1244 } 1245 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1246 } 1247 if (drawHasse) { 1248 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1249 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1258 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1264 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1265 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1266 } 1267 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1268 1269 /* Plot vertices */ 1270 PetscCall(VecGetArray(coordinates, &coords)); 1271 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1272 for (v = vStart; v < vEnd; ++v) { 1273 PetscInt off, dof, d; 1274 PetscBool isLabeled = PETSC_FALSE; 1275 1276 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1277 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1278 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1280 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1281 for (d = 0; d < dof; ++d) { 1282 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1283 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1284 } 1285 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1286 if (dim == 3) { 1287 PetscReal tmp = tcoords[1]; 1288 tcoords[1] = tcoords[2]; 1289 tcoords[2] = -tmp; 1290 } 1291 for (d = 0; d < dof; ++d) { 1292 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1293 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1294 } 1295 if (drawHasse) color = colors[0 % numColors]; 1296 else color = colors[rank % numColors]; 1297 for (l = 0; l < numLabels; ++l) { 1298 PetscInt val; 1299 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1300 if (val >= 0) { 1301 color = lcolors[l % numLColors]; 1302 isLabeled = PETSC_TRUE; 1303 break; 1304 } 1305 } 1306 if (drawNumbers[0]) { 1307 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1308 } else if (drawColors[0]) { 1309 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1310 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1311 } 1312 PetscCall(VecRestoreArray(coordinates, &coords)); 1313 PetscCall(PetscViewerFlush(viewer)); 1314 /* Plot edges */ 1315 if (plotEdges) { 1316 PetscCall(VecGetArray(coordinates, &coords)); 1317 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1318 for (e = eStart; e < eEnd; ++e) { 1319 const PetscInt *cone; 1320 PetscInt coneSize, offA, offB, dof, d; 1321 1322 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1323 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1324 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1325 PetscCall(DMPlexGetCone(dm, e, &cone)); 1326 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1327 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1328 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1329 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1330 for (d = 0; d < dof; ++d) { 1331 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1332 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1333 } 1334 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1335 if (dim == 3) { 1336 PetscReal tmp = tcoords[1]; 1337 tcoords[1] = tcoords[2]; 1338 tcoords[2] = -tmp; 1339 } 1340 for (d = 0; d < dof; ++d) { 1341 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1342 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1343 } 1344 if (drawHasse) color = colors[1 % numColors]; 1345 else color = colors[rank % numColors]; 1346 for (l = 0; l < numLabels; ++l) { 1347 PetscInt val; 1348 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1349 if (val >= 0) { 1350 color = lcolors[l % numLColors]; 1351 break; 1352 } 1353 } 1354 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1355 } 1356 PetscCall(VecRestoreArray(coordinates, &coords)); 1357 PetscCall(PetscViewerFlush(viewer)); 1358 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1359 } 1360 /* Plot cells */ 1361 if (dim == 3 || !drawNumbers[1]) { 1362 for (e = eStart; e < eEnd; ++e) { 1363 const PetscInt *cone; 1364 1365 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1366 color = colors[rank % numColors]; 1367 for (l = 0; l < numLabels; ++l) { 1368 PetscInt val; 1369 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1370 if (val >= 0) { 1371 color = lcolors[l % numLColors]; 1372 break; 1373 } 1374 } 1375 PetscCall(DMPlexGetCone(dm, e, &cone)); 1376 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1377 } 1378 } else { 1379 DMPolytopeType ct; 1380 1381 /* Drawing a 2D polygon */ 1382 for (c = cStart; c < cEnd; ++c) { 1383 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1384 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1385 if (DMPolytopeTypeIsHybrid(ct)) { 1386 const PetscInt *cone; 1387 PetscInt coneSize, e; 1388 1389 PetscCall(DMPlexGetCone(dm, c, &cone)); 1390 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1391 for (e = 0; e < coneSize; ++e) { 1392 const PetscInt *econe; 1393 1394 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1395 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1396 } 1397 } else { 1398 PetscInt *closure = NULL; 1399 PetscInt closureSize, Nv = 0, v; 1400 1401 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1402 for (p = 0; p < closureSize * 2; p += 2) { 1403 const PetscInt point = closure[p]; 1404 1405 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1406 } 1407 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1408 for (v = 0; v <= Nv; ++v) { 1409 const PetscInt vertex = closure[v % Nv]; 1410 1411 if (v > 0) { 1412 if (plotEdges) { 1413 const PetscInt *edge; 1414 PetscInt endpoints[2], ne; 1415 1416 endpoints[0] = closure[v - 1]; 1417 endpoints[1] = vertex; 1418 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1419 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1420 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1421 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1422 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1423 } 1424 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1425 } 1426 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1427 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1428 } 1429 } 1430 } 1431 for (c = cStart; c < cEnd; ++c) { 1432 double ccoords[3] = {0.0, 0.0, 0.0}; 1433 PetscBool isLabeled = PETSC_FALSE; 1434 PetscScalar *cellCoords = NULL; 1435 const PetscScalar *array; 1436 PetscInt numCoords, cdim, d; 1437 PetscBool isDG; 1438 1439 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1440 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1441 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1442 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1443 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1444 for (p = 0; p < numCoords / cdim; ++p) { 1445 for (d = 0; d < cdim; ++d) { 1446 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1447 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1448 } 1449 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1450 if (cdim == 3) { 1451 PetscReal tmp = tcoords[1]; 1452 tcoords[1] = tcoords[2]; 1453 tcoords[2] = -tmp; 1454 } 1455 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1456 } 1457 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1458 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1459 for (d = 0; d < cdim; ++d) { 1460 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1461 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1462 } 1463 if (drawHasse) color = colors[depth % numColors]; 1464 else color = colors[rank % numColors]; 1465 for (l = 0; l < numLabels; ++l) { 1466 PetscInt val; 1467 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1468 if (val >= 0) { 1469 color = lcolors[l % numLColors]; 1470 isLabeled = PETSC_TRUE; 1471 break; 1472 } 1473 } 1474 if (drawNumbers[dim]) { 1475 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1476 } else if (drawColors[dim]) { 1477 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1478 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1479 } 1480 if (drawHasse) { 1481 int height = 0; 1482 1483 color = colors[depth % numColors]; 1484 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1485 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1486 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1487 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1489 1490 if (depth > 2) { 1491 color = colors[1 % numColors]; 1492 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1493 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1494 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1495 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1496 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1497 } 1498 1499 color = colors[1 % numColors]; 1500 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1502 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1503 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1504 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1505 1506 color = colors[0 % numColors]; 1507 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1510 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1511 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1512 1513 for (p = pStart; p < pEnd; ++p) { 1514 const PetscInt *cone; 1515 PetscInt coneSize, cp; 1516 1517 PetscCall(DMPlexGetCone(dm, p, &cone)); 1518 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1519 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1520 } 1521 } 1522 PetscCall(PetscViewerFlush(viewer)); 1523 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1524 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1525 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1526 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1527 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1528 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1529 PetscCall(PetscFree3(names, colors, lcolors)); 1530 PetscCall(PetscBTDestroy(&wp)); 1531 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1532 Vec cown, acown; 1533 VecScatter sct; 1534 ISLocalToGlobalMapping g2l; 1535 IS gid, acis; 1536 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1537 MPI_Group ggroup, ngroup; 1538 PetscScalar *array, nid; 1539 const PetscInt *idxs; 1540 PetscInt *idxs2, *start, *adjacency, *work; 1541 PetscInt64 lm[3], gm[3]; 1542 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1543 PetscMPIInt d1, d2, rank; 1544 1545 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1546 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1547 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1548 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1549 #endif 1550 if (ncomm != MPI_COMM_NULL) { 1551 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1552 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1553 d1 = 0; 1554 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1555 nid = d2; 1556 PetscCallMPI(MPI_Group_free(&ggroup)); 1557 PetscCallMPI(MPI_Group_free(&ngroup)); 1558 PetscCallMPI(MPI_Comm_free(&ncomm)); 1559 } else nid = 0.0; 1560 1561 /* Get connectivity */ 1562 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1563 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1564 1565 /* filter overlapped local cells */ 1566 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1567 PetscCall(ISGetIndices(gid, &idxs)); 1568 PetscCall(ISGetLocalSize(gid, &cum)); 1569 PetscCall(PetscMalloc1(cum, &idxs2)); 1570 for (c = cStart, cum = 0; c < cEnd; c++) { 1571 if (idxs[c - cStart] < 0) continue; 1572 idxs2[cum++] = idxs[c - cStart]; 1573 } 1574 PetscCall(ISRestoreIndices(gid, &idxs)); 1575 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1576 PetscCall(ISDestroy(&gid)); 1577 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1578 1579 /* support for node-aware cell locality */ 1580 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1581 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1582 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1583 PetscCall(VecGetArray(cown, &array)); 1584 for (c = 0; c < numVertices; c++) array[c] = nid; 1585 PetscCall(VecRestoreArray(cown, &array)); 1586 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1587 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1588 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1589 PetscCall(ISDestroy(&acis)); 1590 PetscCall(VecScatterDestroy(&sct)); 1591 PetscCall(VecDestroy(&cown)); 1592 1593 /* compute edgeCut */ 1594 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1595 PetscCall(PetscMalloc1(cum, &work)); 1596 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1597 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1598 PetscCall(ISDestroy(&gid)); 1599 PetscCall(VecGetArray(acown, &array)); 1600 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1601 PetscInt totl; 1602 1603 totl = start[c + 1] - start[c]; 1604 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1605 for (i = 0; i < totl; i++) { 1606 if (work[i] < 0) { 1607 ect += 1; 1608 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1609 } 1610 } 1611 } 1612 PetscCall(PetscFree(work)); 1613 PetscCall(VecRestoreArray(acown, &array)); 1614 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1615 lm[1] = -numVertices; 1616 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1617 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1618 lm[0] = ect; /* edgeCut */ 1619 lm[1] = ectn; /* node-aware edgeCut */ 1620 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1621 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1622 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1623 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1624 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1625 #else 1626 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1627 #endif 1628 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1629 PetscCall(PetscFree(start)); 1630 PetscCall(PetscFree(adjacency)); 1631 PetscCall(VecDestroy(&acown)); 1632 } else { 1633 const char *name; 1634 PetscInt *sizes, *hybsizes, *ghostsizes; 1635 PetscInt locDepth, depth, cellHeight, dim, d; 1636 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1637 PetscInt numLabels, l, maxSize = 17; 1638 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1639 MPI_Comm comm; 1640 PetscMPIInt size, rank; 1641 1642 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1643 PetscCallMPI(MPI_Comm_size(comm, &size)); 1644 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1645 PetscCall(DMGetDimension(dm, &dim)); 1646 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1647 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1648 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1649 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1650 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1651 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1652 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1653 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1654 gcNum = gcEnd - gcStart; 1655 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1656 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1657 for (d = 0; d <= depth; d++) { 1658 PetscInt Nc[2] = {0, 0}, ict; 1659 1660 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1661 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1662 ict = ct0; 1663 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1664 ct0 = (DMPolytopeType)ict; 1665 for (p = pStart; p < pEnd; ++p) { 1666 DMPolytopeType ct; 1667 1668 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1669 if (ct == ct0) ++Nc[0]; 1670 else ++Nc[1]; 1671 } 1672 if (size < maxSize) { 1673 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1674 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1675 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1676 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1677 for (p = 0; p < size; ++p) { 1678 if (rank == 0) { 1679 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1680 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1681 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1682 } 1683 } 1684 } else { 1685 PetscInt locMinMax[2]; 1686 1687 locMinMax[0] = Nc[0] + Nc[1]; 1688 locMinMax[1] = Nc[0] + Nc[1]; 1689 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1690 locMinMax[0] = Nc[1]; 1691 locMinMax[1] = Nc[1]; 1692 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1693 if (d == depth) { 1694 locMinMax[0] = gcNum; 1695 locMinMax[1] = gcNum; 1696 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1697 } 1698 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1699 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1700 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1701 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1702 } 1703 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1704 } 1705 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1706 { 1707 const PetscReal *maxCell; 1708 const PetscReal *L; 1709 PetscBool localized; 1710 1711 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1712 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1713 if (L || localized) { 1714 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1715 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1716 if (L) { 1717 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1718 for (d = 0; d < dim; ++d) { 1719 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1720 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1721 } 1722 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1723 } 1724 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1725 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1726 } 1727 } 1728 PetscCall(DMGetNumLabels(dm, &numLabels)); 1729 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1730 for (l = 0; l < numLabels; ++l) { 1731 DMLabel label; 1732 const char *name; 1733 PetscInt *values; 1734 PetscInt numValues, v; 1735 1736 PetscCall(DMGetLabelName(dm, l, &name)); 1737 PetscCall(DMGetLabel(dm, name, &label)); 1738 PetscCall(DMLabelGetNumValues(label, &numValues)); 1739 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1740 1741 { // Extract array of DMLabel values so it can be sorted 1742 IS is_values; 1743 const PetscInt *is_values_local = NULL; 1744 1745 PetscCall(DMLabelGetValueIS(label, &is_values)); 1746 PetscCall(ISGetIndices(is_values, &is_values_local)); 1747 PetscCall(PetscMalloc1(numValues, &values)); 1748 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1749 PetscCall(PetscSortInt(numValues, values)); 1750 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1751 PetscCall(ISDestroy(&is_values)); 1752 } 1753 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1754 for (v = 0; v < numValues; ++v) { 1755 PetscInt size; 1756 1757 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1758 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1759 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1760 } 1761 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1762 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1763 PetscCall(PetscFree(values)); 1764 } 1765 { 1766 char **labelNames; 1767 PetscInt Nl = numLabels; 1768 PetscBool flg; 1769 1770 PetscCall(PetscMalloc1(Nl, &labelNames)); 1771 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1772 for (l = 0; l < Nl; ++l) { 1773 DMLabel label; 1774 1775 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1776 if (flg) { 1777 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1778 PetscCall(DMLabelView(label, viewer)); 1779 } 1780 PetscCall(PetscFree(labelNames[l])); 1781 } 1782 PetscCall(PetscFree(labelNames)); 1783 } 1784 /* If no fields are specified, people do not want to see adjacency */ 1785 if (dm->Nf) { 1786 PetscInt f; 1787 1788 for (f = 0; f < dm->Nf; ++f) { 1789 const char *name; 1790 1791 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1792 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1793 PetscCall(PetscViewerASCIIPushTab(viewer)); 1794 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1795 if (dm->fields[f].adjacency[0]) { 1796 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1797 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1798 } else { 1799 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1800 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1801 } 1802 PetscCall(PetscViewerASCIIPopTab(viewer)); 1803 } 1804 } 1805 DMPlexTransform tr; 1806 1807 PetscCall(DMPlexGetTransform(dm, &tr)); 1808 if (tr) { 1809 PetscCall(PetscViewerASCIIPushTab(viewer)); 1810 PetscCall(PetscViewerASCIIPrintf(viewer, "Created using transform:\n")); 1811 PetscCall(DMPlexTransformView(tr, viewer)); 1812 PetscCall(PetscViewerASCIIPopTab(viewer)); 1813 } 1814 PetscCall(DMGetCoarseDM(dm, &cdm)); 1815 if (cdm) { 1816 PetscCall(PetscViewerASCIIPushTab(viewer)); 1817 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1818 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1819 PetscCall(PetscViewerASCIIPopTab(viewer)); 1820 } 1821 } 1822 PetscFunctionReturn(PETSC_SUCCESS); 1823 } 1824 1825 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1826 { 1827 DMPolytopeType ct; 1828 PetscMPIInt rank; 1829 PetscInt cdim; 1830 1831 PetscFunctionBegin; 1832 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1833 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1834 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1835 switch (ct) { 1836 case DM_POLYTOPE_SEGMENT: 1837 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1838 switch (cdim) { 1839 case 1: { 1840 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1841 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1842 1843 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1844 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1845 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1846 } break; 1847 case 2: { 1848 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1849 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1850 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1851 1852 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1853 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1854 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1855 } break; 1856 default: 1857 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1858 } 1859 break; 1860 case DM_POLYTOPE_TRIANGLE: 1861 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1862 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1863 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1864 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1865 break; 1866 case DM_POLYTOPE_QUADRILATERAL: 1867 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1868 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1869 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1870 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1871 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1872 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1873 break; 1874 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1875 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1876 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1877 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1878 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1879 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1880 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1881 break; 1882 case DM_POLYTOPE_FV_GHOST: 1883 break; 1884 default: 1885 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1886 } 1887 PetscFunctionReturn(PETSC_SUCCESS); 1888 } 1889 1890 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1891 { 1892 PetscReal centroid[2] = {0., 0.}; 1893 PetscMPIInt rank; 1894 PetscMPIInt fillColor; 1895 1896 PetscFunctionBegin; 1897 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1898 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1899 for (PetscInt v = 0; v < Nv; ++v) { 1900 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1901 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1902 } 1903 for (PetscInt e = 0; e < Nv; ++e) { 1904 refCoords[0] = refVertices[e * 2 + 0]; 1905 refCoords[1] = refVertices[e * 2 + 1]; 1906 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1907 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1908 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1909 } 1910 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1911 for (PetscInt d = 0; d < edgeDiv; ++d) { 1912 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1913 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1914 } 1915 } 1916 PetscFunctionReturn(PETSC_SUCCESS); 1917 } 1918 1919 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1920 { 1921 DMPolytopeType ct; 1922 1923 PetscFunctionBegin; 1924 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1925 switch (ct) { 1926 case DM_POLYTOPE_TRIANGLE: { 1927 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1928 1929 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1930 } break; 1931 case DM_POLYTOPE_QUADRILATERAL: { 1932 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1933 1934 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1935 } break; 1936 default: 1937 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1938 } 1939 PetscFunctionReturn(PETSC_SUCCESS); 1940 } 1941 1942 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1943 { 1944 PetscDraw draw; 1945 DM cdm; 1946 PetscSection coordSection; 1947 Vec coordinates; 1948 PetscReal xyl[3], xyr[3]; 1949 PetscReal *refCoords, *edgeCoords; 1950 PetscBool isnull, drawAffine; 1951 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1952 1953 PetscFunctionBegin; 1954 PetscCall(DMGetCoordinateDim(dm, &dim)); 1955 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1956 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1957 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1958 edgeDiv = cDegree + 1; 1959 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1960 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1961 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1962 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1963 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1964 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1965 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1966 1967 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1968 PetscCall(PetscDrawIsNull(draw, &isnull)); 1969 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1970 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1971 1972 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1973 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1974 PetscCall(PetscDrawClear(draw)); 1975 1976 for (c = cStart; c < cEnd; ++c) { 1977 PetscScalar *coords = NULL; 1978 const PetscScalar *coords_arr; 1979 PetscInt numCoords; 1980 PetscBool isDG; 1981 1982 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1983 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1984 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1985 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1986 } 1987 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1988 PetscCall(PetscDrawFlush(draw)); 1989 PetscCall(PetscDrawPause(draw)); 1990 PetscCall(PetscDrawSave(draw)); 1991 PetscFunctionReturn(PETSC_SUCCESS); 1992 } 1993 1994 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1995 { 1996 DM odm = dm, rdm = dm, cdm; 1997 PetscFE fe; 1998 PetscSpace sp; 1999 PetscClassId id; 2000 PetscInt degree; 2001 PetscBool hoView = PETSC_TRUE; 2002 2003 PetscFunctionBegin; 2004 PetscObjectOptionsBegin((PetscObject)dm); 2005 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 2006 PetscOptionsEnd(); 2007 PetscCall(PetscObjectReference((PetscObject)dm)); 2008 *hdm = dm; 2009 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 2010 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2011 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 2012 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 2013 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 2014 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 2015 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 2016 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 2017 DM cdm, rcdm; 2018 Mat In; 2019 Vec cl, rcl; 2020 2021 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 2022 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 2023 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 2024 PetscCall(DMGetCoordinateDM(odm, &cdm)); 2025 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 2026 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 2027 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 2028 PetscCall(DMSetCoarseDM(rcdm, cdm)); 2029 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 2030 PetscCall(MatMult(In, cl, rcl)); 2031 PetscCall(MatDestroy(&In)); 2032 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 2033 PetscCall(DMDestroy(&odm)); 2034 odm = rdm; 2035 } 2036 *hdm = rdm; 2037 PetscFunctionReturn(PETSC_SUCCESS); 2038 } 2039 2040 #if defined(PETSC_HAVE_EXODUSII) 2041 #include <exodusII.h> 2042 #include <petscviewerexodusii.h> 2043 #endif 2044 2045 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 2046 { 2047 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 2048 char name[PETSC_MAX_PATH_LEN]; 2049 2050 PetscFunctionBegin; 2051 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2052 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2053 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 2054 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2055 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2056 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2057 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 2058 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 2059 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 2060 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2061 if (iascii) { 2062 PetscViewerFormat format; 2063 PetscCall(PetscViewerGetFormat(viewer, &format)); 2064 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 2065 else PetscCall(DMPlexView_Ascii(dm, viewer)); 2066 } else if (ishdf5) { 2067 #if defined(PETSC_HAVE_HDF5) 2068 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 2069 #else 2070 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2071 #endif 2072 } else if (isvtk) { 2073 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2074 } else if (isdraw) { 2075 DM hdm; 2076 2077 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2078 PetscCall(DMPlexView_Draw(hdm, viewer)); 2079 PetscCall(DMDestroy(&hdm)); 2080 } else if (isglvis) { 2081 PetscCall(DMPlexView_GLVis(dm, viewer)); 2082 #if defined(PETSC_HAVE_EXODUSII) 2083 } else if (isexodus) { 2084 /* 2085 exodusII requires that all sets be part of exactly one cell set. 2086 If the dm does not have a "Cell Sets" label defined, we create one 2087 with ID 1, containing all cells. 2088 Note that if the Cell Sets label is defined but does not cover all cells, 2089 we may still have a problem. This should probably be checked here or in the viewer; 2090 */ 2091 PetscInt numCS; 2092 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2093 if (!numCS) { 2094 PetscInt cStart, cEnd, c; 2095 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2096 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2097 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2098 } 2099 PetscCall(DMView_PlexExodusII(dm, viewer)); 2100 #endif 2101 #if defined(PETSC_HAVE_CGNS) 2102 } else if (iscgns) { 2103 PetscCall(DMView_PlexCGNS(dm, viewer)); 2104 #endif 2105 } else if (ispython) { 2106 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2107 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2108 /* Optionally view the partition */ 2109 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2110 if (flg) { 2111 Vec ranks; 2112 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2113 PetscCall(VecView(ranks, viewer)); 2114 PetscCall(VecDestroy(&ranks)); 2115 } 2116 /* Optionally view a label */ 2117 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2118 if (flg) { 2119 DMLabel label; 2120 Vec val; 2121 2122 PetscCall(DMGetLabel(dm, name, &label)); 2123 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2124 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2125 PetscCall(VecView(val, viewer)); 2126 PetscCall(VecDestroy(&val)); 2127 } 2128 PetscFunctionReturn(PETSC_SUCCESS); 2129 } 2130 2131 /*@ 2132 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2133 2134 Collective 2135 2136 Input Parameters: 2137 + dm - The `DM` whose topology is to be saved 2138 - viewer - The `PetscViewer` to save it in 2139 2140 Level: advanced 2141 2142 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2143 @*/ 2144 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2145 { 2146 PetscBool ishdf5; 2147 2148 PetscFunctionBegin; 2149 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2150 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2151 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2152 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2153 if (ishdf5) { 2154 #if defined(PETSC_HAVE_HDF5) 2155 PetscViewerFormat format; 2156 PetscCall(PetscViewerGetFormat(viewer, &format)); 2157 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2158 IS globalPointNumbering; 2159 2160 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2161 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2162 PetscCall(ISDestroy(&globalPointNumbering)); 2163 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2164 #else 2165 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2166 #endif 2167 } 2168 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2169 PetscFunctionReturn(PETSC_SUCCESS); 2170 } 2171 2172 /*@ 2173 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2174 2175 Collective 2176 2177 Input Parameters: 2178 + dm - The `DM` whose coordinates are to be saved 2179 - viewer - The `PetscViewer` for saving 2180 2181 Level: advanced 2182 2183 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2184 @*/ 2185 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2186 { 2187 PetscBool ishdf5; 2188 2189 PetscFunctionBegin; 2190 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2191 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2192 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2193 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2194 if (ishdf5) { 2195 #if defined(PETSC_HAVE_HDF5) 2196 PetscViewerFormat format; 2197 PetscCall(PetscViewerGetFormat(viewer, &format)); 2198 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2199 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2200 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2201 #else 2202 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2203 #endif 2204 } 2205 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2206 PetscFunctionReturn(PETSC_SUCCESS); 2207 } 2208 2209 /*@ 2210 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2211 2212 Collective 2213 2214 Input Parameters: 2215 + dm - The `DM` whose labels are to be saved 2216 - viewer - The `PetscViewer` for saving 2217 2218 Level: advanced 2219 2220 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2221 @*/ 2222 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2223 { 2224 PetscBool ishdf5; 2225 2226 PetscFunctionBegin; 2227 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2228 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2229 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2230 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2231 if (ishdf5) { 2232 #if defined(PETSC_HAVE_HDF5) 2233 IS globalPointNumbering; 2234 PetscViewerFormat format; 2235 2236 PetscCall(PetscViewerGetFormat(viewer, &format)); 2237 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2238 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2239 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2240 PetscCall(ISDestroy(&globalPointNumbering)); 2241 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2242 #else 2243 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2244 #endif 2245 } 2246 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2247 PetscFunctionReturn(PETSC_SUCCESS); 2248 } 2249 2250 /*@ 2251 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2252 2253 Collective 2254 2255 Input Parameters: 2256 + dm - The `DM` that contains the topology on which the section to be saved is defined 2257 . viewer - The `PetscViewer` for saving 2258 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2259 2260 Level: advanced 2261 2262 Notes: 2263 This function is a wrapper around `PetscSectionView()`; in addition to the raw section, it saves information that associates the section points to the topology (`dm`) points. When the topology (`dm`) and the section are later loaded with `DMPlexTopologyLoad()` and `DMPlexSectionLoad()`, respectively, this information is used to match section points with topology points. 2264 2265 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2266 2267 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2268 @*/ 2269 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2270 { 2271 PetscBool ishdf5; 2272 2273 PetscFunctionBegin; 2274 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2275 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2276 if (!sectiondm) sectiondm = dm; 2277 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2278 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2279 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2280 if (ishdf5) { 2281 #if defined(PETSC_HAVE_HDF5) 2282 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2283 #else 2284 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2285 #endif 2286 } 2287 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2288 PetscFunctionReturn(PETSC_SUCCESS); 2289 } 2290 2291 /*@ 2292 DMPlexGlobalVectorView - Saves a global vector 2293 2294 Collective 2295 2296 Input Parameters: 2297 + dm - The `DM` that represents the topology 2298 . viewer - The `PetscViewer` to save data with 2299 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2300 - vec - The global vector to be saved 2301 2302 Level: advanced 2303 2304 Notes: 2305 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2306 2307 Calling sequence: 2308 .vb 2309 DMCreate(PETSC_COMM_WORLD, &dm); 2310 DMSetType(dm, DMPLEX); 2311 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2312 DMClone(dm, §iondm); 2313 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2314 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2315 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2316 PetscSectionSetChart(section, pStart, pEnd); 2317 PetscSectionSetUp(section); 2318 DMSetLocalSection(sectiondm, section); 2319 PetscSectionDestroy(§ion); 2320 DMGetGlobalVector(sectiondm, &vec); 2321 PetscObjectSetName((PetscObject)vec, "vec_name"); 2322 DMPlexTopologyView(dm, viewer); 2323 DMPlexSectionView(dm, viewer, sectiondm); 2324 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2325 DMRestoreGlobalVector(sectiondm, &vec); 2326 DMDestroy(§iondm); 2327 DMDestroy(&dm); 2328 .ve 2329 2330 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2331 @*/ 2332 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2333 { 2334 PetscBool ishdf5; 2335 2336 PetscFunctionBegin; 2337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2338 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2339 if (!sectiondm) sectiondm = dm; 2340 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2341 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2342 /* Check consistency */ 2343 { 2344 PetscSection section; 2345 PetscBool includesConstraints; 2346 PetscInt m, m1; 2347 2348 PetscCall(VecGetLocalSize(vec, &m1)); 2349 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2350 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2351 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2352 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2353 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2354 } 2355 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2356 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2357 if (ishdf5) { 2358 #if defined(PETSC_HAVE_HDF5) 2359 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2360 #else 2361 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2362 #endif 2363 } 2364 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2365 PetscFunctionReturn(PETSC_SUCCESS); 2366 } 2367 2368 /*@ 2369 DMPlexLocalVectorView - Saves a local vector 2370 2371 Collective 2372 2373 Input Parameters: 2374 + dm - The `DM` that represents the topology 2375 . viewer - The `PetscViewer` to save data with 2376 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2377 - vec - The local vector to be saved 2378 2379 Level: advanced 2380 2381 Note: 2382 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2383 2384 Calling sequence: 2385 .vb 2386 DMCreate(PETSC_COMM_WORLD, &dm); 2387 DMSetType(dm, DMPLEX); 2388 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2389 DMClone(dm, §iondm); 2390 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2391 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2392 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2393 PetscSectionSetChart(section, pStart, pEnd); 2394 PetscSectionSetUp(section); 2395 DMSetLocalSection(sectiondm, section); 2396 DMGetLocalVector(sectiondm, &vec); 2397 PetscObjectSetName((PetscObject)vec, "vec_name"); 2398 DMPlexTopologyView(dm, viewer); 2399 DMPlexSectionView(dm, viewer, sectiondm); 2400 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2401 DMRestoreLocalVector(sectiondm, &vec); 2402 DMDestroy(§iondm); 2403 DMDestroy(&dm); 2404 .ve 2405 2406 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2407 @*/ 2408 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2409 { 2410 PetscBool ishdf5; 2411 2412 PetscFunctionBegin; 2413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2414 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2415 if (!sectiondm) sectiondm = dm; 2416 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2417 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2418 /* Check consistency */ 2419 { 2420 PetscSection section; 2421 PetscBool includesConstraints; 2422 PetscInt m, m1; 2423 2424 PetscCall(VecGetLocalSize(vec, &m1)); 2425 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2426 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2427 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2428 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2429 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2430 } 2431 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2432 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2433 if (ishdf5) { 2434 #if defined(PETSC_HAVE_HDF5) 2435 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2436 #else 2437 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2438 #endif 2439 } 2440 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2441 PetscFunctionReturn(PETSC_SUCCESS); 2442 } 2443 2444 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2445 { 2446 PetscBool ishdf5; 2447 2448 PetscFunctionBegin; 2449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2450 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2451 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2452 if (ishdf5) { 2453 #if defined(PETSC_HAVE_HDF5) 2454 PetscViewerFormat format; 2455 PetscCall(PetscViewerGetFormat(viewer, &format)); 2456 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2457 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2458 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2459 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2460 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2461 PetscFunctionReturn(PETSC_SUCCESS); 2462 #else 2463 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2464 #endif 2465 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2466 } 2467 2468 /*@ 2469 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2470 2471 Collective 2472 2473 Input Parameters: 2474 + dm - The `DM` into which the topology is loaded 2475 - viewer - The `PetscViewer` for the saved topology 2476 2477 Output Parameter: 2478 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; 2479 `NULL` if unneeded 2480 2481 Level: advanced 2482 2483 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2484 `PetscViewer`, `PetscSF` 2485 @*/ 2486 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2487 { 2488 PetscBool ishdf5; 2489 2490 PetscFunctionBegin; 2491 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2492 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2493 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2494 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2495 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2496 if (ishdf5) { 2497 #if defined(PETSC_HAVE_HDF5) 2498 PetscViewerFormat format; 2499 PetscCall(PetscViewerGetFormat(viewer, &format)); 2500 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2501 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2502 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2503 #else 2504 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2505 #endif 2506 } 2507 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2508 PetscFunctionReturn(PETSC_SUCCESS); 2509 } 2510 2511 /*@ 2512 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2513 2514 Collective 2515 2516 Input Parameters: 2517 + dm - The `DM` into which the coordinates are loaded 2518 . viewer - The `PetscViewer` for the saved coordinates 2519 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2520 2521 Level: advanced 2522 2523 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2524 `PetscSF`, `PetscViewer` 2525 @*/ 2526 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2527 { 2528 PetscBool ishdf5; 2529 2530 PetscFunctionBegin; 2531 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2532 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2533 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2534 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2535 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2536 if (ishdf5) { 2537 #if defined(PETSC_HAVE_HDF5) 2538 PetscViewerFormat format; 2539 PetscCall(PetscViewerGetFormat(viewer, &format)); 2540 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2541 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2542 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2543 #else 2544 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2545 #endif 2546 } 2547 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2548 PetscFunctionReturn(PETSC_SUCCESS); 2549 } 2550 2551 /*@ 2552 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2553 2554 Collective 2555 2556 Input Parameters: 2557 + dm - The `DM` into which the labels are loaded 2558 . viewer - The `PetscViewer` for the saved labels 2559 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2560 2561 Level: advanced 2562 2563 Note: 2564 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2565 2566 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2567 `PetscSF`, `PetscViewer` 2568 @*/ 2569 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2570 { 2571 PetscBool ishdf5; 2572 2573 PetscFunctionBegin; 2574 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2575 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2576 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2577 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2578 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2579 if (ishdf5) { 2580 #if defined(PETSC_HAVE_HDF5) 2581 PetscViewerFormat format; 2582 2583 PetscCall(PetscViewerGetFormat(viewer, &format)); 2584 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2585 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2586 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2587 #else 2588 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2589 #endif 2590 } 2591 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2592 PetscFunctionReturn(PETSC_SUCCESS); 2593 } 2594 2595 /*@ 2596 DMPlexSectionLoad - Loads section into a `DMPLEX` 2597 2598 Collective 2599 2600 Input Parameters: 2601 + dm - The `DM` that represents the topology 2602 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2603 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2604 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2605 2606 Output Parameters: 2607 + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed) 2608 - localDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed) 2609 2610 Level: advanced 2611 2612 Notes: 2613 This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2614 2615 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2616 2617 The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2618 2619 Example using 2 processes: 2620 .vb 2621 NX (number of points on dm): 4 2622 sectionA : the on-disk section 2623 vecA : a vector associated with sectionA 2624 sectionB : sectiondm's local section constructed in this function 2625 vecB (local) : a vector associated with sectiondm's local section 2626 vecB (global) : a vector associated with sectiondm's global section 2627 2628 rank 0 rank 1 2629 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2630 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2631 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2632 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2633 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2634 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2635 sectionB->atlasDof : 1 0 1 | 1 3 2636 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2637 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2638 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2639 .ve 2640 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2641 2642 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2643 @*/ 2644 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, PeOp DM sectiondm, PetscSF globalToLocalPointSF, PeOp PetscSF *globalDofSF, PeOp PetscSF *localDofSF) 2645 { 2646 PetscBool ishdf5; 2647 2648 PetscFunctionBegin; 2649 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2650 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2651 if (!sectiondm) sectiondm = dm; 2652 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2653 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2654 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2655 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2656 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2657 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2658 if (ishdf5) { 2659 #if defined(PETSC_HAVE_HDF5) 2660 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2661 #else 2662 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2663 #endif 2664 } 2665 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2666 PetscFunctionReturn(PETSC_SUCCESS); 2667 } 2668 2669 /*@ 2670 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2671 2672 Collective 2673 2674 Input Parameters: 2675 + dm - The `DM` that represents the topology 2676 . viewer - The `PetscViewer` that represents the on-disk vector data 2677 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2678 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2679 - vec - The global vector to set values of 2680 2681 Level: advanced 2682 2683 Notes: 2684 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2685 2686 Calling sequence: 2687 .vb 2688 DMCreate(PETSC_COMM_WORLD, &dm); 2689 DMSetType(dm, DMPLEX); 2690 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2691 DMPlexTopologyLoad(dm, viewer, &sfX); 2692 DMClone(dm, §iondm); 2693 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2694 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2695 DMGetGlobalVector(sectiondm, &vec); 2696 PetscObjectSetName((PetscObject)vec, "vec_name"); 2697 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2698 DMRestoreGlobalVector(sectiondm, &vec); 2699 PetscSFDestroy(&gsf); 2700 PetscSFDestroy(&sfX); 2701 DMDestroy(§iondm); 2702 DMDestroy(&dm); 2703 .ve 2704 2705 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2706 `PetscSF`, `PetscViewer` 2707 @*/ 2708 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2709 { 2710 PetscBool ishdf5; 2711 2712 PetscFunctionBegin; 2713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2714 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2715 if (!sectiondm) sectiondm = dm; 2716 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2717 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2718 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2719 /* Check consistency */ 2720 { 2721 PetscSection section; 2722 PetscBool includesConstraints; 2723 PetscInt m, m1; 2724 2725 PetscCall(VecGetLocalSize(vec, &m1)); 2726 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2727 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2728 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2729 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2730 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2731 } 2732 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2733 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2734 if (ishdf5) { 2735 #if defined(PETSC_HAVE_HDF5) 2736 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2737 #else 2738 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2739 #endif 2740 } 2741 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2742 PetscFunctionReturn(PETSC_SUCCESS); 2743 } 2744 2745 /*@ 2746 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2747 2748 Collective 2749 2750 Input Parameters: 2751 + dm - The `DM` that represents the topology 2752 . viewer - The `PetscViewer` that represents the on-disk vector data 2753 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2754 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2755 - vec - The local vector to set values of 2756 2757 Level: advanced 2758 2759 Notes: 2760 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2761 2762 Calling sequence: 2763 .vb 2764 DMCreate(PETSC_COMM_WORLD, &dm); 2765 DMSetType(dm, DMPLEX); 2766 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2767 DMPlexTopologyLoad(dm, viewer, &sfX); 2768 DMClone(dm, §iondm); 2769 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2770 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2771 DMGetLocalVector(sectiondm, &vec); 2772 PetscObjectSetName((PetscObject)vec, "vec_name"); 2773 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2774 DMRestoreLocalVector(sectiondm, &vec); 2775 PetscSFDestroy(&lsf); 2776 PetscSFDestroy(&sfX); 2777 DMDestroy(§iondm); 2778 DMDestroy(&dm); 2779 .ve 2780 2781 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2782 `PetscSF`, `PetscViewer` 2783 @*/ 2784 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2785 { 2786 PetscBool ishdf5; 2787 2788 PetscFunctionBegin; 2789 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2790 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2791 if (!sectiondm) sectiondm = dm; 2792 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2793 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2794 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2795 /* Check consistency */ 2796 { 2797 PetscSection section; 2798 PetscBool includesConstraints; 2799 PetscInt m, m1; 2800 2801 PetscCall(VecGetLocalSize(vec, &m1)); 2802 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2803 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2804 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2805 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2806 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2807 } 2808 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2809 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2810 if (ishdf5) { 2811 #if defined(PETSC_HAVE_HDF5) 2812 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2813 #else 2814 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2815 #endif 2816 } 2817 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2818 PetscFunctionReturn(PETSC_SUCCESS); 2819 } 2820 2821 PetscErrorCode DMDestroy_Plex(DM dm) 2822 { 2823 DM_Plex *mesh = (DM_Plex *)dm->data; 2824 2825 PetscFunctionBegin; 2826 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2827 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2828 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2829 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2830 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2831 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2832 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2833 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2834 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2835 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2836 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2837 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2838 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2839 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2840 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2841 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2842 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2843 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2844 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2845 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2846 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2847 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2848 PetscCall(PetscFree(mesh->cones)); 2849 PetscCall(PetscFree(mesh->coneOrientations)); 2850 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2851 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2852 PetscCall(PetscFree(mesh->supports)); 2853 PetscCall(PetscFree(mesh->cellTypes)); 2854 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2855 PetscCall(PetscFree(mesh->tetgenOpts)); 2856 PetscCall(PetscFree(mesh->triangleOpts)); 2857 PetscCall(PetscFree(mesh->transformType)); 2858 PetscCall(PetscFree(mesh->distributionName)); 2859 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2860 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2861 PetscCall(ISDestroy(&mesh->subpointIS)); 2862 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2863 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2864 if (mesh->periodic.face_sfs) { 2865 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2866 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2867 } 2868 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2869 if (mesh->periodic.periodic_points) { 2870 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2871 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2872 } 2873 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2874 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2875 PetscCall(ISDestroy(&mesh->anchorIS)); 2876 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2877 PetscCall(PetscFree(mesh->parents)); 2878 PetscCall(PetscFree(mesh->childIDs)); 2879 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2880 PetscCall(PetscFree(mesh->children)); 2881 PetscCall(DMDestroy(&mesh->referenceTree)); 2882 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2883 PetscCall(PetscFree(mesh->neighbors)); 2884 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2885 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2886 PetscCall(DMPlexTransformDestroy(&mesh->transform)); 2887 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2888 PetscCall(PetscFree(mesh)); 2889 PetscFunctionReturn(PETSC_SUCCESS); 2890 } 2891 2892 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2893 { 2894 PetscSection sectionGlobal, sectionLocal; 2895 PetscInt bs = -1, mbs; 2896 PetscInt localSize, localStart = 0; 2897 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2898 MatType mtype; 2899 ISLocalToGlobalMapping ltog; 2900 2901 PetscFunctionBegin; 2902 PetscCall(MatInitializePackage()); 2903 mtype = dm->mattype; 2904 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2905 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2906 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2907 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2908 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2909 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2910 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2911 PetscCall(MatSetType(*J, mtype)); 2912 PetscCall(MatSetFromOptions(*J)); 2913 PetscCall(MatGetBlockSize(*J, &mbs)); 2914 if (mbs > 1) bs = mbs; 2915 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2916 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2917 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2918 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2919 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2920 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2921 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2922 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2923 if (!isShell) { 2924 // There are three states with pblocks, since block starts can have no dofs: 2925 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2926 // TRUE) Block Start: The first entry in a block has been added 2927 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2928 PetscBT blst; 2929 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2930 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2931 const PetscInt *perm = NULL; 2932 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2933 PetscInt pStart, pEnd, dof, cdof, num_fields; 2934 2935 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2936 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2937 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2938 2939 PetscCall(PetscCalloc1(localSize, &pblocks)); 2940 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2941 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2942 // We need to process in the permuted order to get block sizes right 2943 for (PetscInt point = pStart; point < pEnd; ++point) { 2944 const PetscInt p = perm ? perm[point] : point; 2945 2946 switch (dm->blocking_type) { 2947 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2948 PetscInt bdof, offset; 2949 2950 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2951 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2952 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2953 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2954 if (dof > 0) { 2955 // State change 2956 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2957 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2958 2959 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2960 // Signal block concatenation 2961 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2962 } 2963 dof = dof < 0 ? -(dof + 1) : dof; 2964 bdof = cdof && (dof - cdof) ? 1 : dof; 2965 if (dof) { 2966 if (bs < 0) { 2967 bs = bdof; 2968 } else if (bs != bdof) { 2969 bs = 1; 2970 } 2971 } 2972 } break; 2973 case DM_BLOCKING_FIELD_NODE: { 2974 for (PetscInt field = 0; field < num_fields; field++) { 2975 PetscInt num_comp, bdof, offset; 2976 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2977 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2978 if (dof < 0) continue; 2979 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2980 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2981 PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp); 2982 PetscInt num_nodes = dof / num_comp; 2983 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2984 // Handle possibly constant block size (unlikely) 2985 bdof = cdof && (dof - cdof) ? 1 : dof; 2986 if (dof) { 2987 if (bs < 0) { 2988 bs = bdof; 2989 } else if (bs != bdof) { 2990 bs = 1; 2991 } 2992 } 2993 } 2994 } break; 2995 } 2996 } 2997 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2998 /* Must have same blocksize on all procs (some might have no points) */ 2999 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 3000 bsLocal[1] = bs; 3001 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 3002 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 3003 else bs = bsMinMax[0]; 3004 bs = PetscMax(1, bs); 3005 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 3006 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 3007 PetscCall(MatSetBlockSize(*J, bs)); 3008 PetscCall(MatSetUp(*J)); 3009 } else { 3010 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 3011 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 3012 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 3013 } 3014 if (pblocks) { // Consolidate blocks 3015 PetscInt nblocks = 0; 3016 pblocks[0] = PetscAbs(pblocks[0]); 3017 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 3018 if (pblocks[i] == 0) continue; 3019 // Negative block size indicates the blocks should be concatenated 3020 if (pblocks[i] < 0) { 3021 pblocks[i] = -pblocks[i]; 3022 pblocks[nblocks - 1] += pblocks[i]; 3023 } else { 3024 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 3025 } 3026 for (PetscInt j = 1; j < pblocks[i]; j++) 3027 PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j); 3028 } 3029 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 3030 } 3031 PetscCall(PetscFree(pblocks)); 3032 } 3033 PetscCall(MatSetDM(*J, dm)); 3034 PetscFunctionReturn(PETSC_SUCCESS); 3035 } 3036 3037 /*@ 3038 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 3039 3040 Not Collective 3041 3042 Input Parameter: 3043 . dm - The `DMPLEX` 3044 3045 Output Parameter: 3046 . subsection - The subdomain section 3047 3048 Level: developer 3049 3050 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 3051 @*/ 3052 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 3053 { 3054 DM_Plex *mesh = (DM_Plex *)dm->data; 3055 3056 PetscFunctionBegin; 3057 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3058 if (!mesh->subdomainSection) { 3059 PetscSection section; 3060 PetscSF sf; 3061 3062 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 3063 PetscCall(DMGetLocalSection(dm, §ion)); 3064 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 3065 PetscCall(PetscSFDestroy(&sf)); 3066 } 3067 *subsection = mesh->subdomainSection; 3068 PetscFunctionReturn(PETSC_SUCCESS); 3069 } 3070 3071 /*@ 3072 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 3073 3074 Not Collective 3075 3076 Input Parameter: 3077 . dm - The `DMPLEX` 3078 3079 Output Parameters: 3080 + pStart - The first mesh point 3081 - pEnd - The upper bound for mesh points 3082 3083 Level: beginner 3084 3085 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3086 @*/ 3087 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3088 { 3089 DM_Plex *mesh = (DM_Plex *)dm->data; 3090 3091 PetscFunctionBegin; 3092 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3093 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3094 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3095 PetscFunctionReturn(PETSC_SUCCESS); 3096 } 3097 3098 /*@ 3099 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3100 3101 Not Collective 3102 3103 Input Parameters: 3104 + dm - The `DMPLEX` 3105 . pStart - The first mesh point 3106 - pEnd - The upper bound for mesh points 3107 3108 Level: beginner 3109 3110 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3111 @*/ 3112 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3113 { 3114 DM_Plex *mesh = (DM_Plex *)dm->data; 3115 3116 PetscFunctionBegin; 3117 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3118 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3119 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3120 PetscCall(PetscFree(mesh->cellTypes)); 3121 PetscFunctionReturn(PETSC_SUCCESS); 3122 } 3123 3124 /*@ 3125 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3126 3127 Not Collective 3128 3129 Input Parameters: 3130 + dm - The `DMPLEX` 3131 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3132 3133 Output Parameter: 3134 . size - The cone size for point `p` 3135 3136 Level: beginner 3137 3138 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3139 @*/ 3140 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3141 { 3142 DM_Plex *mesh = (DM_Plex *)dm->data; 3143 3144 PetscFunctionBegin; 3145 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3146 PetscAssertPointer(size, 3); 3147 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3148 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3149 PetscFunctionReturn(PETSC_SUCCESS); 3150 } 3151 3152 /*@ 3153 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3154 3155 Not Collective 3156 3157 Input Parameters: 3158 + dm - The `DMPLEX` 3159 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3160 - size - The cone size for point `p` 3161 3162 Level: beginner 3163 3164 Note: 3165 This should be called after `DMPlexSetChart()`. 3166 3167 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3168 @*/ 3169 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3170 { 3171 DM_Plex *mesh = (DM_Plex *)dm->data; 3172 3173 PetscFunctionBegin; 3174 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3175 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3176 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3177 PetscFunctionReturn(PETSC_SUCCESS); 3178 } 3179 3180 /*@C 3181 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3182 3183 Not Collective 3184 3185 Input Parameters: 3186 + dm - The `DMPLEX` 3187 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3188 3189 Output Parameter: 3190 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3191 3192 Level: beginner 3193 3194 Fortran Notes: 3195 `cone` must be declared with 3196 .vb 3197 PetscInt, pointer :: cone(:) 3198 .ve 3199 3200 You must also call `DMPlexRestoreCone()` after you finish using the array. 3201 `DMPlexRestoreCone()` is not needed/available in C. 3202 3203 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3204 @*/ 3205 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3206 { 3207 DM_Plex *mesh = (DM_Plex *)dm->data; 3208 PetscInt off; 3209 3210 PetscFunctionBegin; 3211 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3212 PetscAssertPointer(cone, 3); 3213 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3214 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3215 PetscFunctionReturn(PETSC_SUCCESS); 3216 } 3217 3218 /*@ 3219 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3220 3221 Not Collective 3222 3223 Input Parameters: 3224 + dm - The `DMPLEX` 3225 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3226 3227 Output Parameters: 3228 + pConesSection - `PetscSection` describing the layout of `pCones` 3229 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3230 3231 Level: intermediate 3232 3233 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3234 @*/ 3235 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PeOp PetscSection *pConesSection, PeOp IS *pCones) 3236 { 3237 PetscSection cs, newcs; 3238 PetscInt *cones; 3239 PetscInt *newarr = NULL; 3240 PetscInt n; 3241 3242 PetscFunctionBegin; 3243 PetscCall(DMPlexGetCones(dm, &cones)); 3244 PetscCall(DMPlexGetConeSection(dm, &cs)); 3245 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3246 if (pConesSection) *pConesSection = newcs; 3247 if (pCones) { 3248 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3249 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3250 } 3251 PetscFunctionReturn(PETSC_SUCCESS); 3252 } 3253 3254 /*@ 3255 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3256 3257 Not Collective 3258 3259 Input Parameters: 3260 + dm - The `DMPLEX` 3261 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3262 3263 Output Parameter: 3264 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3265 3266 Level: advanced 3267 3268 Notes: 3269 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3270 3271 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3272 3273 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3274 `DMPlexGetDepth()`, `IS` 3275 @*/ 3276 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3277 { 3278 IS *expandedPointsAll; 3279 PetscInt depth; 3280 3281 PetscFunctionBegin; 3282 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3283 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3284 PetscAssertPointer(expandedPoints, 3); 3285 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3286 *expandedPoints = expandedPointsAll[0]; 3287 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3288 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3289 PetscFunctionReturn(PETSC_SUCCESS); 3290 } 3291 3292 /*@ 3293 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3294 (DAG points of depth 0, i.e., without cones). 3295 3296 Not Collective 3297 3298 Input Parameters: 3299 + dm - The `DMPLEX` 3300 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3301 3302 Output Parameters: 3303 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3304 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3305 - sections - (optional) An array of sections which describe mappings from points to their cone points 3306 3307 Level: advanced 3308 3309 Notes: 3310 Like `DMPlexGetConeTuple()` but recursive. 3311 3312 Array `expandedPoints` has size equal to `depth`. Each `expandedPoints`[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 3313 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3314 3315 Array section has size equal to `depth`. Each `PetscSection` `sections`[d] realizes mapping from `expandedPoints`[d+1] (section points) to `expandedPoints`[d] (section dofs) as follows\: 3316 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3317 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3318 3319 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3320 `DMPlexGetDepth()`, `PetscSection`, `IS` 3321 @*/ 3322 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3323 { 3324 const PetscInt *arr0 = NULL, *cone = NULL; 3325 PetscInt *arr = NULL, *newarr = NULL; 3326 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3327 IS *expandedPoints_; 3328 PetscSection *sections_; 3329 3330 PetscFunctionBegin; 3331 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3332 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3333 if (depth) PetscAssertPointer(depth, 3); 3334 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3335 if (sections) PetscAssertPointer(sections, 5); 3336 PetscCall(ISGetLocalSize(points, &n)); 3337 PetscCall(ISGetIndices(points, &arr0)); 3338 PetscCall(DMPlexGetDepth(dm, &depth_)); 3339 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3340 PetscCall(PetscCalloc1(depth_, §ions_)); 3341 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3342 for (d = depth_ - 1; d >= 0; d--) { 3343 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3344 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3345 for (i = 0; i < n; i++) { 3346 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3347 if (arr[i] >= start && arr[i] < end) { 3348 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3349 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3350 } else { 3351 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3352 } 3353 } 3354 PetscCall(PetscSectionSetUp(sections_[d])); 3355 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3356 PetscCall(PetscMalloc1(newn, &newarr)); 3357 for (i = 0; i < n; i++) { 3358 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3359 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3360 if (cn > 1) { 3361 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3362 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3363 } else { 3364 newarr[co] = arr[i]; 3365 } 3366 } 3367 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3368 arr = newarr; 3369 n = newn; 3370 } 3371 PetscCall(ISRestoreIndices(points, &arr0)); 3372 *depth = depth_; 3373 if (expandedPoints) *expandedPoints = expandedPoints_; 3374 else { 3375 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3376 PetscCall(PetscFree(expandedPoints_)); 3377 } 3378 if (sections) *sections = sections_; 3379 else { 3380 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3381 PetscCall(PetscFree(sections_)); 3382 } 3383 PetscFunctionReturn(PETSC_SUCCESS); 3384 } 3385 3386 /*@ 3387 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3388 3389 Not Collective 3390 3391 Input Parameters: 3392 + dm - The `DMPLEX` 3393 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3394 3395 Output Parameters: 3396 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3397 . expandedPoints - (optional) An array of recursively expanded cones 3398 - sections - (optional) An array of sections which describe mappings from points to their cone points 3399 3400 Level: advanced 3401 3402 Note: 3403 See `DMPlexGetConeRecursive()` 3404 3405 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3406 `DMPlexGetDepth()`, `IS`, `PetscSection` 3407 @*/ 3408 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3409 { 3410 PetscInt d, depth_; 3411 3412 PetscFunctionBegin; 3413 PetscCall(DMPlexGetDepth(dm, &depth_)); 3414 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3415 if (depth) *depth = 0; 3416 if (expandedPoints) { 3417 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3418 PetscCall(PetscFree(*expandedPoints)); 3419 } 3420 if (sections) { 3421 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3422 PetscCall(PetscFree(*sections)); 3423 } 3424 PetscFunctionReturn(PETSC_SUCCESS); 3425 } 3426 3427 /*@ 3428 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 3429 3430 Not Collective 3431 3432 Input Parameters: 3433 + dm - The `DMPLEX` 3434 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3435 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3436 3437 Level: beginner 3438 3439 Note: 3440 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3441 3442 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3443 @*/ 3444 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3445 { 3446 DM_Plex *mesh = (DM_Plex *)dm->data; 3447 PetscInt dof, off, c; 3448 3449 PetscFunctionBegin; 3450 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3451 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3452 if (dof) PetscAssertPointer(cone, 3); 3453 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3454 if (PetscDefined(USE_DEBUG)) { 3455 PetscInt pStart, pEnd; 3456 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3457 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3458 for (c = 0; c < dof; ++c) { 3459 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3460 mesh->cones[off + c] = cone[c]; 3461 } 3462 } else { 3463 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3464 } 3465 PetscFunctionReturn(PETSC_SUCCESS); 3466 } 3467 3468 /*@C 3469 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3470 3471 Not Collective 3472 3473 Input Parameters: 3474 + dm - The `DMPLEX` 3475 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3476 3477 Output Parameter: 3478 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3479 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3480 3481 Level: beginner 3482 3483 Note: 3484 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3485 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3486 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3487 with the identity. 3488 3489 Fortran Notes: 3490 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3491 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3492 3493 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3494 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3495 @*/ 3496 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3497 { 3498 DM_Plex *mesh = (DM_Plex *)dm->data; 3499 PetscInt off; 3500 3501 PetscFunctionBegin; 3502 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3503 if (PetscDefined(USE_DEBUG)) { 3504 PetscInt dof; 3505 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3506 if (dof) PetscAssertPointer(coneOrientation, 3); 3507 } 3508 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3509 3510 *coneOrientation = &mesh->coneOrientations[off]; 3511 PetscFunctionReturn(PETSC_SUCCESS); 3512 } 3513 3514 /*@ 3515 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3516 3517 Not Collective 3518 3519 Input Parameters: 3520 + dm - The `DMPLEX` 3521 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3522 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3523 3524 Level: beginner 3525 3526 Notes: 3527 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3528 3529 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3530 3531 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3532 @*/ 3533 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3534 { 3535 DM_Plex *mesh = (DM_Plex *)dm->data; 3536 PetscInt pStart, pEnd; 3537 PetscInt dof, off, c; 3538 3539 PetscFunctionBegin; 3540 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3541 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3542 if (dof) PetscAssertPointer(coneOrientation, 3); 3543 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3544 if (PetscDefined(USE_DEBUG)) { 3545 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3546 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3547 for (c = 0; c < dof; ++c) { 3548 PetscInt cdof, o = coneOrientation[c]; 3549 3550 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3551 PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof); 3552 mesh->coneOrientations[off + c] = o; 3553 } 3554 } else { 3555 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3556 } 3557 PetscFunctionReturn(PETSC_SUCCESS); 3558 } 3559 3560 /*@ 3561 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3562 3563 Not Collective 3564 3565 Input Parameters: 3566 + dm - The `DMPLEX` 3567 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3568 . conePos - The local index in the cone where the point should be put 3569 - conePoint - The mesh point to insert 3570 3571 Level: beginner 3572 3573 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3574 @*/ 3575 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3576 { 3577 DM_Plex *mesh = (DM_Plex *)dm->data; 3578 PetscInt pStart, pEnd; 3579 PetscInt dof, off; 3580 3581 PetscFunctionBegin; 3582 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3583 if (PetscDefined(USE_DEBUG)) { 3584 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3585 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3586 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3587 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3588 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3589 } 3590 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3591 mesh->cones[off + conePos] = conePoint; 3592 PetscFunctionReturn(PETSC_SUCCESS); 3593 } 3594 3595 /*@ 3596 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3597 3598 Not Collective 3599 3600 Input Parameters: 3601 + dm - The `DMPLEX` 3602 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3603 . conePos - The local index in the cone where the point should be put 3604 - coneOrientation - The point orientation to insert 3605 3606 Level: beginner 3607 3608 Note: 3609 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3610 3611 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3612 @*/ 3613 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3614 { 3615 DM_Plex *mesh = (DM_Plex *)dm->data; 3616 PetscInt pStart, pEnd; 3617 PetscInt dof, off; 3618 3619 PetscFunctionBegin; 3620 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3621 if (PetscDefined(USE_DEBUG)) { 3622 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3623 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3624 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3625 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3626 } 3627 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3628 mesh->coneOrientations[off + conePos] = coneOrientation; 3629 PetscFunctionReturn(PETSC_SUCCESS); 3630 } 3631 3632 /*@C 3633 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3634 3635 Not collective 3636 3637 Input Parameters: 3638 + dm - The DMPlex 3639 - p - The point, which must lie in the chart set with DMPlexSetChart() 3640 3641 Output Parameters: 3642 + cone - An array of points which are on the in-edges for point `p` 3643 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3644 integer giving the prescription for cone traversal. 3645 3646 Level: beginner 3647 3648 Notes: 3649 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3650 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3651 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3652 with the identity. 3653 3654 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3655 3656 Fortran Notes: 3657 `cone` and `ornt` must be declared with 3658 .vb 3659 PetscInt, pointer :: cone(:) 3660 PetscInt, pointer :: ornt(:) 3661 .ve 3662 3663 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3664 @*/ 3665 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, PeOp const PetscInt *cone[], PeOp const PetscInt *ornt[]) 3666 { 3667 DM_Plex *mesh = (DM_Plex *)dm->data; 3668 3669 PetscFunctionBegin; 3670 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3671 if (mesh->tr) { 3672 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3673 } else { 3674 PetscInt off; 3675 if (PetscDefined(USE_DEBUG)) { 3676 PetscInt dof; 3677 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3678 if (dof) { 3679 if (cone) PetscAssertPointer(cone, 3); 3680 if (ornt) PetscAssertPointer(ornt, 4); 3681 } 3682 } 3683 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3684 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3685 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3686 } 3687 PetscFunctionReturn(PETSC_SUCCESS); 3688 } 3689 3690 /*@C 3691 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3692 3693 Not Collective 3694 3695 Input Parameters: 3696 + dm - The DMPlex 3697 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3698 . cone - An array of points which are on the in-edges for point p 3699 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3700 integer giving the prescription for cone traversal. 3701 3702 Level: beginner 3703 3704 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3705 @*/ 3706 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3707 { 3708 DM_Plex *mesh = (DM_Plex *)dm->data; 3709 3710 PetscFunctionBegin; 3711 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3712 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3713 PetscFunctionReturn(PETSC_SUCCESS); 3714 } 3715 3716 /*@ 3717 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3718 3719 Not Collective 3720 3721 Input Parameters: 3722 + dm - The `DMPLEX` 3723 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3724 3725 Output Parameter: 3726 . size - The support size for point `p` 3727 3728 Level: beginner 3729 3730 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3731 @*/ 3732 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3733 { 3734 DM_Plex *mesh = (DM_Plex *)dm->data; 3735 3736 PetscFunctionBegin; 3737 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3738 PetscAssertPointer(size, 3); 3739 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3740 PetscFunctionReturn(PETSC_SUCCESS); 3741 } 3742 3743 /*@ 3744 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3745 3746 Not Collective 3747 3748 Input Parameters: 3749 + dm - The `DMPLEX` 3750 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3751 - size - The support size for point `p` 3752 3753 Level: beginner 3754 3755 Note: 3756 This should be called after `DMPlexSetChart()`. 3757 3758 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3759 @*/ 3760 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3761 { 3762 DM_Plex *mesh = (DM_Plex *)dm->data; 3763 3764 PetscFunctionBegin; 3765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3766 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3767 PetscFunctionReturn(PETSC_SUCCESS); 3768 } 3769 3770 /*@C 3771 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3772 3773 Not Collective 3774 3775 Input Parameters: 3776 + dm - The `DMPLEX` 3777 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3778 3779 Output Parameter: 3780 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3781 3782 Level: beginner 3783 3784 Fortran Notes: 3785 `support` must be declared with 3786 .vb 3787 PetscInt, pointer :: support(:) 3788 .ve 3789 3790 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3791 `DMPlexRestoreSupport()` is not needed/available in C. 3792 3793 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3794 @*/ 3795 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3796 { 3797 DM_Plex *mesh = (DM_Plex *)dm->data; 3798 PetscInt off; 3799 3800 PetscFunctionBegin; 3801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3802 PetscAssertPointer(support, 3); 3803 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3804 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3805 PetscFunctionReturn(PETSC_SUCCESS); 3806 } 3807 3808 /*@ 3809 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3810 3811 Not Collective 3812 3813 Input Parameters: 3814 + dm - The `DMPLEX` 3815 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3816 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3817 3818 Level: beginner 3819 3820 Note: 3821 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3822 3823 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3824 @*/ 3825 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3826 { 3827 DM_Plex *mesh = (DM_Plex *)dm->data; 3828 PetscInt pStart, pEnd; 3829 PetscInt dof, off, c; 3830 3831 PetscFunctionBegin; 3832 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3833 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3834 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3835 if (dof) PetscAssertPointer(support, 3); 3836 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3837 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3838 for (c = 0; c < dof; ++c) { 3839 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3840 mesh->supports[off + c] = support[c]; 3841 } 3842 PetscFunctionReturn(PETSC_SUCCESS); 3843 } 3844 3845 /*@ 3846 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3847 3848 Not Collective 3849 3850 Input Parameters: 3851 + dm - The `DMPLEX` 3852 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3853 . supportPos - The local index in the cone where the point should be put 3854 - supportPoint - The mesh point to insert 3855 3856 Level: beginner 3857 3858 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3859 @*/ 3860 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3861 { 3862 DM_Plex *mesh = (DM_Plex *)dm->data; 3863 PetscInt pStart, pEnd; 3864 PetscInt dof, off; 3865 3866 PetscFunctionBegin; 3867 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3868 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3869 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3870 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3871 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3872 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3873 PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3874 mesh->supports[off + supportPos] = supportPoint; 3875 PetscFunctionReturn(PETSC_SUCCESS); 3876 } 3877 3878 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3879 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3880 { 3881 switch (ct) { 3882 case DM_POLYTOPE_SEGMENT: 3883 if (o == -1) return -2; 3884 break; 3885 case DM_POLYTOPE_TRIANGLE: 3886 if (o == -3) return -1; 3887 if (o == -2) return -3; 3888 if (o == -1) return -2; 3889 break; 3890 case DM_POLYTOPE_QUADRILATERAL: 3891 if (o == -4) return -2; 3892 if (o == -3) return -1; 3893 if (o == -2) return -4; 3894 if (o == -1) return -3; 3895 break; 3896 default: 3897 return o; 3898 } 3899 return o; 3900 } 3901 3902 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3903 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3904 { 3905 switch (ct) { 3906 case DM_POLYTOPE_SEGMENT: 3907 if ((o == -2) || (o == 1)) return -1; 3908 if (o == -1) return 0; 3909 break; 3910 case DM_POLYTOPE_TRIANGLE: 3911 if (o == -3) return -2; 3912 if (o == -2) return -1; 3913 if (o == -1) return -3; 3914 break; 3915 case DM_POLYTOPE_QUADRILATERAL: 3916 if (o == -4) return -2; 3917 if (o == -3) return -1; 3918 if (o == -2) return -4; 3919 if (o == -1) return -3; 3920 break; 3921 default: 3922 return o; 3923 } 3924 return o; 3925 } 3926 3927 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3928 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3929 { 3930 PetscInt pStart, pEnd, p; 3931 3932 PetscFunctionBegin; 3933 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3934 for (p = pStart; p < pEnd; ++p) { 3935 const PetscInt *cone, *ornt; 3936 PetscInt coneSize, c; 3937 3938 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3939 PetscCall(DMPlexGetCone(dm, p, &cone)); 3940 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3941 for (c = 0; c < coneSize; ++c) { 3942 DMPolytopeType ct; 3943 const PetscInt o = ornt[c]; 3944 3945 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3946 switch (ct) { 3947 case DM_POLYTOPE_SEGMENT: 3948 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3949 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3950 break; 3951 case DM_POLYTOPE_TRIANGLE: 3952 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3953 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3954 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3955 break; 3956 case DM_POLYTOPE_QUADRILATERAL: 3957 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3958 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3959 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3960 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3961 break; 3962 default: 3963 break; 3964 } 3965 } 3966 } 3967 PetscFunctionReturn(PETSC_SUCCESS); 3968 } 3969 3970 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3971 { 3972 DM_Plex *mesh = (DM_Plex *)dm->data; 3973 3974 PetscFunctionBeginHot; 3975 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3976 if (useCone) { 3977 PetscCall(DMPlexGetConeSize(dm, p, size)); 3978 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3979 } else { 3980 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3981 PetscCall(DMPlexGetSupport(dm, p, arr)); 3982 } 3983 } else { 3984 if (useCone) { 3985 const PetscSection s = mesh->coneSection; 3986 const PetscInt ps = p - s->pStart; 3987 const PetscInt off = s->atlasOff[ps]; 3988 3989 *size = s->atlasDof[ps]; 3990 *arr = mesh->cones + off; 3991 *ornt = mesh->coneOrientations + off; 3992 } else { 3993 const PetscSection s = mesh->supportSection; 3994 const PetscInt ps = p - s->pStart; 3995 const PetscInt off = s->atlasOff[ps]; 3996 3997 *size = s->atlasDof[ps]; 3998 *arr = mesh->supports + off; 3999 } 4000 } 4001 PetscFunctionReturn(PETSC_SUCCESS); 4002 } 4003 4004 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 4005 { 4006 DM_Plex *mesh = (DM_Plex *)dm->data; 4007 4008 PetscFunctionBeginHot; 4009 if (PetscDefined(USE_DEBUG) || mesh->tr) { 4010 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 4011 } 4012 PetscFunctionReturn(PETSC_SUCCESS); 4013 } 4014 4015 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4016 { 4017 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4018 PetscInt *closure; 4019 const PetscInt *tmp = NULL, *tmpO = NULL; 4020 PetscInt off = 0, tmpSize, t; 4021 4022 PetscFunctionBeginHot; 4023 if (ornt) { 4024 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4025 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 4026 } 4027 if (*points) { 4028 closure = *points; 4029 } else { 4030 PetscInt maxConeSize, maxSupportSize; 4031 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4032 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 4033 } 4034 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4035 if (ct == DM_POLYTOPE_UNKNOWN) { 4036 closure[off++] = p; 4037 closure[off++] = 0; 4038 for (t = 0; t < tmpSize; ++t) { 4039 closure[off++] = tmp[t]; 4040 closure[off++] = tmpO ? tmpO[t] : 0; 4041 } 4042 } else { 4043 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 4044 4045 /* We assume that cells with a valid type have faces with a valid type */ 4046 closure[off++] = p; 4047 closure[off++] = ornt; 4048 for (t = 0; t < tmpSize; ++t) { 4049 DMPolytopeType ft; 4050 4051 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 4052 closure[off++] = tmp[arr[t]]; 4053 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 4054 } 4055 } 4056 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4057 if (numPoints) *numPoints = tmpSize + 1; 4058 if (points) *points = closure; 4059 PetscFunctionReturn(PETSC_SUCCESS); 4060 } 4061 4062 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 4063 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 4064 { 4065 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 4066 const PetscInt *cone, *ornt; 4067 PetscInt *pts, *closure = NULL; 4068 DMPolytopeType ft; 4069 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 4070 PetscInt dim, coneSize, c, d, clSize, cl; 4071 4072 PetscFunctionBeginHot; 4073 PetscCall(DMGetDimension(dm, &dim)); 4074 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4075 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4076 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4077 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4078 maxSize = PetscMax(coneSeries, supportSeries); 4079 if (*points) { 4080 pts = *points; 4081 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4082 c = 0; 4083 pts[c++] = point; 4084 pts[c++] = o; 4085 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4086 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4087 for (cl = 0; cl < clSize * 2; cl += 2) { 4088 pts[c++] = closure[cl]; 4089 pts[c++] = closure[cl + 1]; 4090 } 4091 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4092 for (cl = 0; cl < clSize * 2; cl += 2) { 4093 pts[c++] = closure[cl]; 4094 pts[c++] = closure[cl + 1]; 4095 } 4096 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4097 for (d = 2; d < coneSize; ++d) { 4098 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4099 pts[c++] = cone[arr[d * 2 + 0]]; 4100 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4101 } 4102 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4103 if (dim >= 3) { 4104 for (d = 2; d < coneSize; ++d) { 4105 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4106 const PetscInt *fcone, *fornt; 4107 PetscInt fconeSize, fc, i; 4108 4109 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4110 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4111 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4112 for (fc = 0; fc < fconeSize; ++fc) { 4113 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4114 const PetscInt co = farr[fc * 2 + 1]; 4115 4116 for (i = 0; i < c; i += 2) 4117 if (pts[i] == cp) break; 4118 if (i == c) { 4119 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4120 pts[c++] = cp; 4121 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4122 } 4123 } 4124 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4125 } 4126 } 4127 *numPoints = c / 2; 4128 *points = pts; 4129 PetscFunctionReturn(PETSC_SUCCESS); 4130 } 4131 4132 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4133 { 4134 DMPolytopeType ct; 4135 PetscInt *closure, *fifo; 4136 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4137 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4138 PetscInt depth, maxSize; 4139 4140 PetscFunctionBeginHot; 4141 PetscCall(DMPlexGetDepth(dm, &depth)); 4142 if (depth == 1) { 4143 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4144 PetscFunctionReturn(PETSC_SUCCESS); 4145 } 4146 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4147 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 4148 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4149 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4150 PetscFunctionReturn(PETSC_SUCCESS); 4151 } 4152 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4153 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4154 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4155 maxSize = PetscMax(coneSeries, supportSeries); 4156 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4157 if (*points) { 4158 closure = *points; 4159 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4160 closure[closureSize++] = p; 4161 closure[closureSize++] = ornt; 4162 fifo[fifoSize++] = p; 4163 fifo[fifoSize++] = ornt; 4164 fifo[fifoSize++] = ct; 4165 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4166 while (fifoSize - fifoStart) { 4167 const PetscInt q = fifo[fifoStart++]; 4168 const PetscInt o = fifo[fifoStart++]; 4169 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4170 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4171 const PetscInt *tmp, *tmpO = NULL; 4172 PetscInt tmpSize, t; 4173 4174 if (PetscDefined(USE_DEBUG)) { 4175 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4176 PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 4177 } 4178 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4179 for (t = 0; t < tmpSize; ++t) { 4180 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4181 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4182 const PetscInt cp = tmp[ip]; 4183 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4184 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4185 PetscInt c; 4186 4187 /* Check for duplicate */ 4188 for (c = 0; c < closureSize; c += 2) { 4189 if (closure[c] == cp) break; 4190 } 4191 if (c == closureSize) { 4192 closure[closureSize++] = cp; 4193 closure[closureSize++] = co; 4194 fifo[fifoSize++] = cp; 4195 fifo[fifoSize++] = co; 4196 fifo[fifoSize++] = ct; 4197 } 4198 } 4199 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4200 } 4201 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4202 if (numPoints) *numPoints = closureSize / 2; 4203 if (points) *points = closure; 4204 PetscFunctionReturn(PETSC_SUCCESS); 4205 } 4206 4207 /*@C 4208 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4209 4210 Not Collective 4211 4212 Input Parameters: 4213 + dm - The `DMPLEX` 4214 . p - The mesh point 4215 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4216 4217 Input/Output Parameter: 4218 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4219 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4220 otherwise the provided array is used to hold the values 4221 4222 Output Parameter: 4223 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4224 4225 Level: beginner 4226 4227 Note: 4228 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4229 4230 Fortran Notes: 4231 `points` must be declared with 4232 .vb 4233 PetscInt, pointer :: points(:) 4234 .ve 4235 and is always allocated by the function. 4236 4237 The `numPoints` argument is not present in the Fortran binding. 4238 4239 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4240 @*/ 4241 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4242 { 4243 PetscFunctionBeginHot; 4244 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4245 if (numPoints) PetscAssertPointer(numPoints, 4); 4246 if (points) PetscAssertPointer(points, 5); 4247 if (PetscDefined(USE_DEBUG)) { 4248 PetscInt pStart, pEnd; 4249 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4250 PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 4251 } 4252 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4253 PetscFunctionReturn(PETSC_SUCCESS); 4254 } 4255 4256 /*@C 4257 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4258 4259 Not Collective 4260 4261 Input Parameters: 4262 + dm - The `DMPLEX` 4263 . p - The mesh point 4264 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4265 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4266 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4267 4268 Level: beginner 4269 4270 Note: 4271 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4272 4273 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4274 @*/ 4275 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4276 { 4277 PetscFunctionBeginHot; 4278 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4279 if (numPoints) *numPoints = 0; 4280 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4281 PetscFunctionReturn(PETSC_SUCCESS); 4282 } 4283 4284 /*@ 4285 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4286 4287 Not Collective 4288 4289 Input Parameter: 4290 . dm - The `DMPLEX` 4291 4292 Output Parameters: 4293 + maxConeSize - The maximum number of in-edges 4294 - maxSupportSize - The maximum number of out-edges 4295 4296 Level: beginner 4297 4298 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4299 @*/ 4300 PetscErrorCode DMPlexGetMaxSizes(DM dm, PeOp PetscInt *maxConeSize, PeOp PetscInt *maxSupportSize) 4301 { 4302 DM_Plex *mesh = (DM_Plex *)dm->data; 4303 4304 PetscFunctionBegin; 4305 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4306 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4307 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4308 PetscFunctionReturn(PETSC_SUCCESS); 4309 } 4310 4311 PetscErrorCode DMSetUp_Plex(DM dm) 4312 { 4313 DM_Plex *mesh = (DM_Plex *)dm->data; 4314 PetscInt size, maxSupportSize; 4315 4316 PetscFunctionBegin; 4317 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4318 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4319 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4320 PetscCall(PetscMalloc1(size, &mesh->cones)); 4321 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4322 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4323 if (maxSupportSize) { 4324 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4325 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4326 PetscCall(PetscMalloc1(size, &mesh->supports)); 4327 } 4328 PetscFunctionReturn(PETSC_SUCCESS); 4329 } 4330 4331 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4332 { 4333 PetscFunctionBegin; 4334 if (subdm) PetscCall(DMClone(dm, subdm)); 4335 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4336 if (subdm) (*subdm)->useNatural = dm->useNatural; 4337 if (dm->useNatural && dm->sfMigration) { 4338 PetscSF sfNatural; 4339 4340 (*subdm)->sfMigration = dm->sfMigration; 4341 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4342 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4343 (*subdm)->sfNatural = sfNatural; 4344 } 4345 PetscFunctionReturn(PETSC_SUCCESS); 4346 } 4347 4348 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4349 { 4350 PetscInt i = 0; 4351 4352 PetscFunctionBegin; 4353 PetscCall(DMClone(dms[0], superdm)); 4354 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4355 (*superdm)->useNatural = PETSC_FALSE; 4356 for (i = 0; i < len; i++) { 4357 if (dms[i]->useNatural && dms[i]->sfMigration) { 4358 PetscSF sfNatural; 4359 4360 (*superdm)->sfMigration = dms[i]->sfMigration; 4361 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4362 (*superdm)->useNatural = PETSC_TRUE; 4363 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4364 (*superdm)->sfNatural = sfNatural; 4365 break; 4366 } 4367 } 4368 PetscFunctionReturn(PETSC_SUCCESS); 4369 } 4370 4371 /*@ 4372 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4373 4374 Not Collective 4375 4376 Input Parameter: 4377 . dm - The `DMPLEX` 4378 4379 Level: beginner 4380 4381 Note: 4382 This should be called after all calls to `DMPlexSetCone()` 4383 4384 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4385 @*/ 4386 PetscErrorCode DMPlexSymmetrize(DM dm) 4387 { 4388 DM_Plex *mesh = (DM_Plex *)dm->data; 4389 PetscInt *offsets; 4390 PetscInt supportSize; 4391 PetscInt pStart, pEnd, p; 4392 4393 PetscFunctionBegin; 4394 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4395 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4396 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4397 /* Calculate support sizes */ 4398 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4399 for (p = pStart; p < pEnd; ++p) { 4400 PetscInt dof, off, c; 4401 4402 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4403 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4404 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4405 } 4406 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4407 /* Calculate supports */ 4408 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4409 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4410 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4411 for (p = pStart; p < pEnd; ++p) { 4412 PetscInt dof, off, c; 4413 4414 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4415 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4416 for (c = off; c < off + dof; ++c) { 4417 const PetscInt q = mesh->cones[c]; 4418 PetscInt offS; 4419 4420 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4421 4422 mesh->supports[offS + offsets[q]] = p; 4423 ++offsets[q]; 4424 } 4425 } 4426 PetscCall(PetscFree(offsets)); 4427 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4428 PetscFunctionReturn(PETSC_SUCCESS); 4429 } 4430 4431 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4432 { 4433 IS stratumIS; 4434 4435 PetscFunctionBegin; 4436 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4437 if (PetscDefined(USE_DEBUG)) { 4438 PetscInt qStart, qEnd, numLevels, level; 4439 PetscBool overlap = PETSC_FALSE; 4440 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4441 for (level = 0; level < numLevels; level++) { 4442 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4443 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4444 overlap = PETSC_TRUE; 4445 break; 4446 } 4447 } 4448 PetscCheck(!overlap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd); 4449 } 4450 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4451 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4452 PetscCall(ISDestroy(&stratumIS)); 4453 PetscFunctionReturn(PETSC_SUCCESS); 4454 } 4455 4456 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4457 { 4458 PetscInt *pMin, *pMax; 4459 PetscInt pStart, pEnd; 4460 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4461 4462 PetscFunctionBegin; 4463 { 4464 DMLabel label2; 4465 4466 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4467 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4468 } 4469 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4470 for (PetscInt p = pStart; p < pEnd; ++p) { 4471 DMPolytopeType ct; 4472 4473 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4474 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4475 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4476 } 4477 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4478 for (PetscInt d = dmin; d <= dmax; ++d) { 4479 pMin[d] = PETSC_INT_MAX; 4480 pMax[d] = PETSC_INT_MIN; 4481 } 4482 for (PetscInt p = pStart; p < pEnd; ++p) { 4483 DMPolytopeType ct; 4484 PetscInt d; 4485 4486 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4487 d = DMPolytopeTypeGetDim(ct); 4488 pMin[d] = PetscMin(p, pMin[d]); 4489 pMax[d] = PetscMax(p, pMax[d]); 4490 } 4491 for (PetscInt d = dmin; d <= dmax; ++d) { 4492 if (pMin[d] > pMax[d]) continue; 4493 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4494 } 4495 PetscCall(PetscFree2(pMin, pMax)); 4496 PetscFunctionReturn(PETSC_SUCCESS); 4497 } 4498 4499 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4500 { 4501 PetscInt pStart, pEnd; 4502 PetscInt numRoots = 0, numLeaves = 0; 4503 4504 PetscFunctionBegin; 4505 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4506 { 4507 /* Initialize roots and count leaves */ 4508 PetscInt sMin = PETSC_INT_MAX; 4509 PetscInt sMax = PETSC_INT_MIN; 4510 PetscInt coneSize, supportSize; 4511 4512 for (PetscInt p = pStart; p < pEnd; ++p) { 4513 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4514 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4515 if (!coneSize && supportSize) { 4516 sMin = PetscMin(p, sMin); 4517 sMax = PetscMax(p, sMax); 4518 ++numRoots; 4519 } else if (!supportSize && coneSize) { 4520 ++numLeaves; 4521 } else if (!supportSize && !coneSize) { 4522 /* Isolated points */ 4523 sMin = PetscMin(p, sMin); 4524 sMax = PetscMax(p, sMax); 4525 } 4526 } 4527 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4528 } 4529 4530 if (numRoots + numLeaves == (pEnd - pStart)) { 4531 PetscInt sMin = PETSC_INT_MAX; 4532 PetscInt sMax = PETSC_INT_MIN; 4533 PetscInt coneSize, supportSize; 4534 4535 for (PetscInt p = pStart; p < pEnd; ++p) { 4536 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4537 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4538 if (!supportSize && coneSize) { 4539 sMin = PetscMin(p, sMin); 4540 sMax = PetscMax(p, sMax); 4541 } 4542 } 4543 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4544 } else { 4545 PetscInt level = 0; 4546 PetscInt qStart, qEnd; 4547 4548 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4549 while (qEnd > qStart) { 4550 PetscInt sMin = PETSC_INT_MAX; 4551 PetscInt sMax = PETSC_INT_MIN; 4552 4553 for (PetscInt q = qStart; q < qEnd; ++q) { 4554 const PetscInt *support; 4555 PetscInt supportSize; 4556 4557 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4558 PetscCall(DMPlexGetSupport(dm, q, &support)); 4559 for (PetscInt s = 0; s < supportSize; ++s) { 4560 sMin = PetscMin(support[s], sMin); 4561 sMax = PetscMax(support[s], sMax); 4562 } 4563 } 4564 PetscCall(DMLabelGetNumValues(label, &level)); 4565 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4566 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4567 } 4568 } 4569 PetscFunctionReturn(PETSC_SUCCESS); 4570 } 4571 4572 /*@ 4573 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4574 4575 Collective 4576 4577 Input Parameter: 4578 . dm - The `DMPLEX` 4579 4580 Level: beginner 4581 4582 Notes: 4583 The strata group all points of the same grade, and this function calculates the strata. This 4584 grade can be seen as the height (or depth) of the point in the DAG. 4585 4586 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4587 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4588 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4589 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4590 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4591 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4592 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4593 4594 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4595 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4596 we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose 4597 to interpolate only that one (e0), so that 4598 .vb 4599 cone(c0) = {e0, v2} 4600 cone(e0) = {v0, v1} 4601 .ve 4602 If `DMPlexStratify()` is run on this mesh, it will give depths 4603 .vb 4604 depth 0 = {v0, v1, v2} 4605 depth 1 = {e0, c0} 4606 .ve 4607 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4608 4609 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4610 4611 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4612 @*/ 4613 PetscErrorCode DMPlexStratify(DM dm) 4614 { 4615 DM_Plex *mesh = (DM_Plex *)dm->data; 4616 DMLabel label; 4617 PetscBool flg = PETSC_FALSE; 4618 4619 PetscFunctionBegin; 4620 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4621 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4622 4623 // Create depth label 4624 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4625 PetscCall(DMCreateLabel(dm, "depth")); 4626 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4627 4628 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4629 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4630 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4631 4632 { /* just in case there is an empty process */ 4633 PetscInt numValues, maxValues = 0, v; 4634 4635 PetscCall(DMLabelGetNumValues(label, &numValues)); 4636 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4637 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4638 } 4639 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4640 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4641 PetscFunctionReturn(PETSC_SUCCESS); 4642 } 4643 4644 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4645 { 4646 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4647 PetscInt dim, depth, pheight, coneSize; 4648 PetscBool preferTensor; 4649 4650 PetscFunctionBeginHot; 4651 PetscCall(DMGetDimension(dm, &dim)); 4652 PetscCall(DMPlexGetDepth(dm, &depth)); 4653 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4654 PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor)); 4655 pheight = depth - pdepth; 4656 if (depth <= 1) { 4657 switch (pdepth) { 4658 case 0: 4659 ct = DM_POLYTOPE_POINT; 4660 break; 4661 case 1: 4662 switch (coneSize) { 4663 case 2: 4664 ct = DM_POLYTOPE_SEGMENT; 4665 break; 4666 case 3: 4667 ct = DM_POLYTOPE_TRIANGLE; 4668 break; 4669 case 4: 4670 switch (dim) { 4671 case 2: 4672 ct = DM_POLYTOPE_QUADRILATERAL; 4673 break; 4674 case 3: 4675 ct = DM_POLYTOPE_TETRAHEDRON; 4676 break; 4677 default: 4678 break; 4679 } 4680 break; 4681 case 5: 4682 ct = DM_POLYTOPE_PYRAMID; 4683 break; 4684 case 6: 4685 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4686 break; 4687 case 8: 4688 ct = DM_POLYTOPE_HEXAHEDRON; 4689 break; 4690 default: 4691 break; 4692 } 4693 } 4694 } else { 4695 if (pdepth == 0) { 4696 ct = DM_POLYTOPE_POINT; 4697 } else if (pheight == 0) { 4698 switch (dim) { 4699 case 1: 4700 switch (coneSize) { 4701 case 2: 4702 ct = DM_POLYTOPE_SEGMENT; 4703 break; 4704 default: 4705 break; 4706 } 4707 break; 4708 case 2: 4709 switch (coneSize) { 4710 case 3: 4711 ct = DM_POLYTOPE_TRIANGLE; 4712 break; 4713 case 4: 4714 ct = DM_POLYTOPE_QUADRILATERAL; 4715 break; 4716 default: 4717 break; 4718 } 4719 break; 4720 case 3: 4721 switch (coneSize) { 4722 case 4: 4723 ct = DM_POLYTOPE_TETRAHEDRON; 4724 break; 4725 case 5: { 4726 const PetscInt *cone; 4727 PetscInt faceConeSize; 4728 4729 PetscCall(DMPlexGetCone(dm, p, &cone)); 4730 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4731 switch (faceConeSize) { 4732 case 3: 4733 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4734 break; 4735 case 4: 4736 ct = DM_POLYTOPE_PYRAMID; 4737 break; 4738 } 4739 } break; 4740 case 6: 4741 ct = DM_POLYTOPE_HEXAHEDRON; 4742 break; 4743 default: 4744 break; 4745 } 4746 break; 4747 default: 4748 break; 4749 } 4750 } else if (pheight > 0) { 4751 switch (coneSize) { 4752 case 2: 4753 ct = DM_POLYTOPE_SEGMENT; 4754 break; 4755 case 3: 4756 ct = DM_POLYTOPE_TRIANGLE; 4757 break; 4758 case 4: 4759 ct = DM_POLYTOPE_QUADRILATERAL; 4760 break; 4761 default: 4762 break; 4763 } 4764 } 4765 } 4766 *pt = ct; 4767 PetscFunctionReturn(PETSC_SUCCESS); 4768 } 4769 4770 /*@ 4771 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4772 4773 Collective 4774 4775 Input Parameter: 4776 . dm - The `DMPLEX` 4777 4778 Level: developer 4779 4780 Note: 4781 This function is normally called automatically when a cell type is requested. It creates an 4782 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4783 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4784 4785 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4786 4787 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4788 @*/ 4789 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4790 { 4791 DM_Plex *mesh; 4792 DMLabel ctLabel; 4793 PetscInt pStart, pEnd, p; 4794 4795 PetscFunctionBegin; 4796 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4797 mesh = (DM_Plex *)dm->data; 4798 PetscCall(DMCreateLabel(dm, "celltype")); 4799 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4800 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4801 PetscCall(PetscFree(mesh->cellTypes)); 4802 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4803 for (p = pStart; p < pEnd; ++p) { 4804 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4805 PetscInt pdepth; 4806 4807 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4808 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4809 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]); 4810 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4811 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4812 } 4813 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4814 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4815 PetscFunctionReturn(PETSC_SUCCESS); 4816 } 4817 4818 /*@C 4819 DMPlexGetJoin - Get an array for the join of the set of points 4820 4821 Not Collective 4822 4823 Input Parameters: 4824 + dm - The `DMPLEX` object 4825 . numPoints - The number of input points for the join 4826 - points - The input points 4827 4828 Output Parameters: 4829 + numCoveredPoints - The number of points in the join 4830 - coveredPoints - The points in the join 4831 4832 Level: intermediate 4833 4834 Note: 4835 Currently, this is restricted to a single level join 4836 4837 Fortran Notes: 4838 `converedPoints` must be declared with 4839 .vb 4840 PetscInt, pointer :: coveredPints(:) 4841 .ve 4842 4843 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4844 @*/ 4845 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4846 { 4847 DM_Plex *mesh = (DM_Plex *)dm->data; 4848 PetscInt *join[2]; 4849 PetscInt joinSize, i = 0; 4850 PetscInt dof, off, p, c, m; 4851 PetscInt maxSupportSize; 4852 4853 PetscFunctionBegin; 4854 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4855 PetscAssertPointer(points, 3); 4856 PetscAssertPointer(numCoveredPoints, 4); 4857 PetscAssertPointer(coveredPoints, 5); 4858 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4859 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4860 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4861 /* Copy in support of first point */ 4862 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4863 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4864 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4865 /* Check each successive support */ 4866 for (p = 1; p < numPoints; ++p) { 4867 PetscInt newJoinSize = 0; 4868 4869 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4870 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4871 for (c = 0; c < dof; ++c) { 4872 const PetscInt point = mesh->supports[off + c]; 4873 4874 for (m = 0; m < joinSize; ++m) { 4875 if (point == join[i][m]) { 4876 join[1 - i][newJoinSize++] = point; 4877 break; 4878 } 4879 } 4880 } 4881 joinSize = newJoinSize; 4882 i = 1 - i; 4883 } 4884 *numCoveredPoints = joinSize; 4885 *coveredPoints = join[i]; 4886 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4887 PetscFunctionReturn(PETSC_SUCCESS); 4888 } 4889 4890 /*@C 4891 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4892 4893 Not Collective 4894 4895 Input Parameters: 4896 + dm - The `DMPLEX` object 4897 . numPoints - The number of input points for the join 4898 - points - The input points 4899 4900 Output Parameters: 4901 + numCoveredPoints - The number of points in the join 4902 - coveredPoints - The points in the join 4903 4904 Level: intermediate 4905 4906 Fortran Notes: 4907 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4908 4909 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4910 @*/ 4911 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4912 { 4913 PetscFunctionBegin; 4914 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4915 if (points) PetscAssertPointer(points, 3); 4916 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4917 PetscAssertPointer(coveredPoints, 5); 4918 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4919 if (numCoveredPoints) *numCoveredPoints = 0; 4920 PetscFunctionReturn(PETSC_SUCCESS); 4921 } 4922 4923 /*@C 4924 DMPlexGetFullJoin - Get an array for the join of the set of points 4925 4926 Not Collective 4927 4928 Input Parameters: 4929 + dm - The `DMPLEX` object 4930 . numPoints - The number of input points for the join 4931 - points - The input points, its length is `numPoints` 4932 4933 Output Parameters: 4934 + numCoveredPoints - The number of points in the join 4935 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4936 4937 Level: intermediate 4938 4939 Fortran Notes: 4940 `points` and `converedPoints` must be declared with 4941 .vb 4942 PetscInt, pointer :: points(:) 4943 PetscInt, pointer :: coveredPints(:) 4944 .ve 4945 4946 The `numCoveredPoints` argument is not present in the Fortran binding. 4947 4948 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4949 @*/ 4950 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4951 { 4952 PetscInt *offsets, **closures; 4953 PetscInt *join[2]; 4954 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4955 PetscInt p, d, c, m, ms; 4956 4957 PetscFunctionBegin; 4958 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4959 PetscAssertPointer(points, 3); 4960 PetscAssertPointer(numCoveredPoints, 4); 4961 PetscAssertPointer(coveredPoints, 5); 4962 4963 PetscCall(DMPlexGetDepth(dm, &depth)); 4964 PetscCall(PetscCalloc1(numPoints, &closures)); 4965 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4966 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4967 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4968 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4969 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4970 4971 for (p = 0; p < numPoints; ++p) { 4972 PetscInt closureSize; 4973 4974 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4975 4976 offsets[p * (depth + 2) + 0] = 0; 4977 for (d = 0; d < depth + 1; ++d) { 4978 PetscInt pStart, pEnd, i; 4979 4980 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4981 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4982 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4983 offsets[p * (depth + 2) + d + 1] = i; 4984 break; 4985 } 4986 } 4987 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4988 } 4989 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); 4990 } 4991 for (d = 0; d < depth + 1; ++d) { 4992 PetscInt dof; 4993 4994 /* Copy in support of first point */ 4995 dof = offsets[d + 1] - offsets[d]; 4996 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4997 /* Check each successive cone */ 4998 for (p = 1; p < numPoints && joinSize; ++p) { 4999 PetscInt newJoinSize = 0; 5000 5001 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 5002 for (c = 0; c < dof; ++c) { 5003 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 5004 5005 for (m = 0; m < joinSize; ++m) { 5006 if (point == join[i][m]) { 5007 join[1 - i][newJoinSize++] = point; 5008 break; 5009 } 5010 } 5011 } 5012 joinSize = newJoinSize; 5013 i = 1 - i; 5014 } 5015 if (joinSize) break; 5016 } 5017 *numCoveredPoints = joinSize; 5018 *coveredPoints = join[i]; 5019 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 5020 PetscCall(PetscFree(closures)); 5021 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 5022 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 5023 PetscFunctionReturn(PETSC_SUCCESS); 5024 } 5025 5026 /*@C 5027 DMPlexGetMeet - Get an array for the meet of the set of points 5028 5029 Not Collective 5030 5031 Input Parameters: 5032 + dm - The `DMPLEX` object 5033 . numPoints - The number of input points for the meet 5034 - points - The input points, of length `numPoints` 5035 5036 Output Parameters: 5037 + numCoveringPoints - The number of points in the meet 5038 - coveringPoints - The points in the meet, of length `numCoveringPoints` 5039 5040 Level: intermediate 5041 5042 Note: 5043 Currently, this is restricted to a single level meet 5044 5045 Fortran Notes: 5046 `coveringPoints` must be declared with 5047 .vb 5048 PetscInt, pointer :: coveringPoints(:) 5049 .ve 5050 5051 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5052 5053 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5054 @*/ 5055 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 5056 { 5057 DM_Plex *mesh = (DM_Plex *)dm->data; 5058 PetscInt *meet[2]; 5059 PetscInt meetSize, i = 0; 5060 PetscInt dof, off, p, c, m; 5061 PetscInt maxConeSize; 5062 5063 PetscFunctionBegin; 5064 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5065 PetscAssertPointer(points, 3); 5066 PetscAssertPointer(numCoveringPoints, 4); 5067 PetscAssertPointer(coveringPoints, 5); 5068 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 5069 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 5070 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 5071 /* Copy in cone of first point */ 5072 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 5073 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 5074 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5075 /* Check each successive cone */ 5076 for (p = 1; p < numPoints; ++p) { 5077 PetscInt newMeetSize = 0; 5078 5079 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5080 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5081 for (c = 0; c < dof; ++c) { 5082 const PetscInt point = mesh->cones[off + c]; 5083 5084 for (m = 0; m < meetSize; ++m) { 5085 if (point == meet[i][m]) { 5086 meet[1 - i][newMeetSize++] = point; 5087 break; 5088 } 5089 } 5090 } 5091 meetSize = newMeetSize; 5092 i = 1 - i; 5093 } 5094 *numCoveringPoints = meetSize; 5095 *coveringPoints = meet[i]; 5096 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5097 PetscFunctionReturn(PETSC_SUCCESS); 5098 } 5099 5100 /*@C 5101 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5102 5103 Not Collective 5104 5105 Input Parameters: 5106 + dm - The `DMPLEX` object 5107 . numPoints - The number of input points for the meet 5108 - points - The input points 5109 5110 Output Parameters: 5111 + numCoveredPoints - The number of points in the meet 5112 - coveredPoints - The points in the meet 5113 5114 Level: intermediate 5115 5116 Fortran Notes: 5117 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5118 5119 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5120 @*/ 5121 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5122 { 5123 PetscFunctionBegin; 5124 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5125 if (points) PetscAssertPointer(points, 3); 5126 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5127 PetscAssertPointer(coveredPoints, 5); 5128 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5129 if (numCoveredPoints) *numCoveredPoints = 0; 5130 PetscFunctionReturn(PETSC_SUCCESS); 5131 } 5132 5133 /*@C 5134 DMPlexGetFullMeet - Get an array for the meet of the set of points 5135 5136 Not Collective 5137 5138 Input Parameters: 5139 + dm - The `DMPLEX` object 5140 . numPoints - The number of input points for the meet 5141 - points - The input points, of length `numPoints` 5142 5143 Output Parameters: 5144 + numCoveredPoints - The number of points in the meet 5145 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5146 5147 Level: intermediate 5148 5149 Fortran Notes: 5150 `points` and `coveredPoints` must be declared with 5151 .vb 5152 PetscInt, pointer :: points(:) 5153 PetscInt, pointer :: coveredPoints(:) 5154 .ve 5155 5156 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5157 5158 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5159 @*/ 5160 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5161 { 5162 PetscInt *offsets, **closures; 5163 PetscInt *meet[2]; 5164 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5165 PetscInt p, h, c, m, mc; 5166 5167 PetscFunctionBegin; 5168 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5169 PetscAssertPointer(points, 3); 5170 PetscAssertPointer(numCoveredPoints, 4); 5171 PetscAssertPointer(coveredPoints, 5); 5172 5173 PetscCall(DMPlexGetDepth(dm, &height)); 5174 PetscCall(PetscMalloc1(numPoints, &closures)); 5175 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5176 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5177 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5178 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5179 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5180 5181 for (p = 0; p < numPoints; ++p) { 5182 PetscInt closureSize; 5183 5184 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5185 5186 offsets[p * (height + 2) + 0] = 0; 5187 for (h = 0; h < height + 1; ++h) { 5188 PetscInt pStart, pEnd, i; 5189 5190 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5191 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5192 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5193 offsets[p * (height + 2) + h + 1] = i; 5194 break; 5195 } 5196 } 5197 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5198 } 5199 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); 5200 } 5201 for (h = 0; h < height + 1; ++h) { 5202 PetscInt dof; 5203 5204 /* Copy in cone of first point */ 5205 dof = offsets[h + 1] - offsets[h]; 5206 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5207 /* Check each successive cone */ 5208 for (p = 1; p < numPoints && meetSize; ++p) { 5209 PetscInt newMeetSize = 0; 5210 5211 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5212 for (c = 0; c < dof; ++c) { 5213 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5214 5215 for (m = 0; m < meetSize; ++m) { 5216 if (point == meet[i][m]) { 5217 meet[1 - i][newMeetSize++] = point; 5218 break; 5219 } 5220 } 5221 } 5222 meetSize = newMeetSize; 5223 i = 1 - i; 5224 } 5225 if (meetSize) break; 5226 } 5227 *numCoveredPoints = meetSize; 5228 *coveredPoints = meet[i]; 5229 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5230 PetscCall(PetscFree(closures)); 5231 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5232 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5233 PetscFunctionReturn(PETSC_SUCCESS); 5234 } 5235 5236 /*@ 5237 DMPlexEqual - Determine if two `DM` have the same topology 5238 5239 Not Collective 5240 5241 Input Parameters: 5242 + dmA - A `DMPLEX` object 5243 - dmB - A `DMPLEX` object 5244 5245 Output Parameter: 5246 . equal - `PETSC_TRUE` if the topologies are identical 5247 5248 Level: intermediate 5249 5250 Note: 5251 We are not solving graph isomorphism, so we do not permute. 5252 5253 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5254 @*/ 5255 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5256 { 5257 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5258 5259 PetscFunctionBegin; 5260 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5261 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5262 PetscAssertPointer(equal, 3); 5263 5264 *equal = PETSC_FALSE; 5265 PetscCall(DMPlexGetDepth(dmA, &depth)); 5266 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5267 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5268 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5269 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5270 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5271 for (p = pStart; p < pEnd; ++p) { 5272 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5273 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5274 5275 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5276 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5277 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5278 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5279 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5280 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5281 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5282 for (c = 0; c < coneSize; ++c) { 5283 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5284 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5285 } 5286 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5287 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5288 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5289 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5290 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5291 for (s = 0; s < supportSize; ++s) { 5292 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5293 } 5294 } 5295 *equal = PETSC_TRUE; 5296 PetscFunctionReturn(PETSC_SUCCESS); 5297 } 5298 5299 /*@ 5300 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5301 5302 Not Collective 5303 5304 Input Parameters: 5305 + dm - The `DMPLEX` 5306 . cellDim - The cell dimension 5307 - numCorners - The number of vertices on a cell 5308 5309 Output Parameter: 5310 . numFaceVertices - The number of vertices on a face 5311 5312 Level: developer 5313 5314 Note: 5315 Of course this can only work for a restricted set of symmetric shapes 5316 5317 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5318 @*/ 5319 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5320 { 5321 MPI_Comm comm; 5322 5323 PetscFunctionBegin; 5324 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5325 PetscAssertPointer(numFaceVertices, 4); 5326 switch (cellDim) { 5327 case 0: 5328 *numFaceVertices = 0; 5329 break; 5330 case 1: 5331 *numFaceVertices = 1; 5332 break; 5333 case 2: 5334 switch (numCorners) { 5335 case 3: /* triangle */ 5336 *numFaceVertices = 2; /* Edge has 2 vertices */ 5337 break; 5338 case 4: /* quadrilateral */ 5339 *numFaceVertices = 2; /* Edge has 2 vertices */ 5340 break; 5341 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5342 *numFaceVertices = 3; /* Edge has 3 vertices */ 5343 break; 5344 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5345 *numFaceVertices = 3; /* Edge has 3 vertices */ 5346 break; 5347 default: 5348 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5349 } 5350 break; 5351 case 3: 5352 switch (numCorners) { 5353 case 4: /* tetradehdron */ 5354 *numFaceVertices = 3; /* Face has 3 vertices */ 5355 break; 5356 case 6: /* tet cohesive cells */ 5357 *numFaceVertices = 4; /* Face has 4 vertices */ 5358 break; 5359 case 8: /* hexahedron */ 5360 *numFaceVertices = 4; /* Face has 4 vertices */ 5361 break; 5362 case 9: /* tet cohesive Lagrange cells */ 5363 *numFaceVertices = 6; /* Face has 6 vertices */ 5364 break; 5365 case 10: /* quadratic tetrahedron */ 5366 *numFaceVertices = 6; /* Face has 6 vertices */ 5367 break; 5368 case 12: /* hex cohesive Lagrange cells */ 5369 *numFaceVertices = 6; /* Face has 6 vertices */ 5370 break; 5371 case 18: /* quadratic tet cohesive Lagrange cells */ 5372 *numFaceVertices = 6; /* Face has 6 vertices */ 5373 break; 5374 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5375 *numFaceVertices = 9; /* Face has 9 vertices */ 5376 break; 5377 default: 5378 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5379 } 5380 break; 5381 default: 5382 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5383 } 5384 PetscFunctionReturn(PETSC_SUCCESS); 5385 } 5386 5387 /*@ 5388 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5389 5390 Not Collective 5391 5392 Input Parameter: 5393 . dm - The `DMPLEX` object 5394 5395 Output Parameter: 5396 . depthLabel - The `DMLabel` recording point depth 5397 5398 Level: developer 5399 5400 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5401 @*/ 5402 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5403 { 5404 PetscFunctionBegin; 5405 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5406 PetscAssertPointer(depthLabel, 2); 5407 *depthLabel = dm->depthLabel; 5408 PetscFunctionReturn(PETSC_SUCCESS); 5409 } 5410 5411 /*@ 5412 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5413 5414 Not Collective 5415 5416 Input Parameter: 5417 . dm - The `DMPLEX` object 5418 5419 Output Parameter: 5420 . depth - The number of strata (breadth first levels) in the DAG 5421 5422 Level: developer 5423 5424 Notes: 5425 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5426 5427 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5428 5429 An empty mesh gives -1. 5430 5431 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5432 @*/ 5433 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5434 { 5435 DM_Plex *mesh = (DM_Plex *)dm->data; 5436 DMLabel label; 5437 PetscInt d = -1; 5438 5439 PetscFunctionBegin; 5440 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5441 PetscAssertPointer(depth, 2); 5442 if (mesh->tr) { 5443 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5444 } else { 5445 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5446 // Allow missing depths 5447 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5448 *depth = d; 5449 } 5450 PetscFunctionReturn(PETSC_SUCCESS); 5451 } 5452 5453 /*@ 5454 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5455 5456 Not Collective 5457 5458 Input Parameters: 5459 + dm - The `DMPLEX` object 5460 - depth - The requested depth 5461 5462 Output Parameters: 5463 + start - The first point at this `depth` 5464 - end - One beyond the last point at this `depth` 5465 5466 Level: developer 5467 5468 Notes: 5469 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5470 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5471 higher dimension, e.g., "edges". 5472 5473 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5474 @*/ 5475 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PeOp PetscInt *start, PeOp PetscInt *end) 5476 { 5477 DM_Plex *mesh = (DM_Plex *)dm->data; 5478 DMLabel label; 5479 PetscInt pStart, pEnd; 5480 5481 PetscFunctionBegin; 5482 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5483 if (start) { 5484 PetscAssertPointer(start, 3); 5485 *start = 0; 5486 } 5487 if (end) { 5488 PetscAssertPointer(end, 4); 5489 *end = 0; 5490 } 5491 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5492 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5493 if (depth < 0) { 5494 if (start) *start = pStart; 5495 if (end) *end = pEnd; 5496 PetscFunctionReturn(PETSC_SUCCESS); 5497 } 5498 if (mesh->tr) { 5499 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5500 } else { 5501 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5502 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5503 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5504 } 5505 PetscFunctionReturn(PETSC_SUCCESS); 5506 } 5507 5508 /*@ 5509 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5510 5511 Not Collective 5512 5513 Input Parameters: 5514 + dm - The `DMPLEX` object 5515 - height - The requested height 5516 5517 Output Parameters: 5518 + start - The first point at this `height` 5519 - end - One beyond the last point at this `height` 5520 5521 Level: developer 5522 5523 Notes: 5524 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5525 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5526 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5527 5528 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5529 @*/ 5530 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PeOp PetscInt *start, PeOp PetscInt *end) 5531 { 5532 DMLabel label; 5533 PetscInt depth, pStart, pEnd; 5534 5535 PetscFunctionBegin; 5536 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5537 if (start) { 5538 PetscAssertPointer(start, 3); 5539 *start = 0; 5540 } 5541 if (end) { 5542 PetscAssertPointer(end, 4); 5543 *end = 0; 5544 } 5545 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5546 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5547 if (height < 0) { 5548 if (start) *start = pStart; 5549 if (end) *end = pEnd; 5550 PetscFunctionReturn(PETSC_SUCCESS); 5551 } 5552 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5553 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5554 else PetscCall(DMGetDimension(dm, &depth)); 5555 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5556 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5557 PetscFunctionReturn(PETSC_SUCCESS); 5558 } 5559 5560 /*@ 5561 DMPlexGetPointDepth - Get the `depth` of a given point 5562 5563 Not Collective 5564 5565 Input Parameters: 5566 + dm - The `DMPLEX` object 5567 - point - The point 5568 5569 Output Parameter: 5570 . depth - The depth of the `point` 5571 5572 Level: intermediate 5573 5574 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5575 @*/ 5576 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5577 { 5578 PetscFunctionBegin; 5579 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5580 PetscAssertPointer(depth, 3); 5581 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5582 PetscFunctionReturn(PETSC_SUCCESS); 5583 } 5584 5585 /*@ 5586 DMPlexGetPointHeight - Get the `height` of a given point 5587 5588 Not Collective 5589 5590 Input Parameters: 5591 + dm - The `DMPLEX` object 5592 - point - The point 5593 5594 Output Parameter: 5595 . height - The height of the `point` 5596 5597 Level: intermediate 5598 5599 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5600 @*/ 5601 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5602 { 5603 PetscInt n, pDepth; 5604 5605 PetscFunctionBegin; 5606 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5607 PetscAssertPointer(height, 3); 5608 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5609 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5610 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5611 PetscFunctionReturn(PETSC_SUCCESS); 5612 } 5613 5614 /*@ 5615 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5616 5617 Not Collective 5618 5619 Input Parameter: 5620 . dm - The `DMPLEX` object 5621 5622 Output Parameter: 5623 . celltypeLabel - The `DMLabel` recording cell polytope type 5624 5625 Level: developer 5626 5627 Note: 5628 This function will trigger automatica computation of cell types. This can be disabled by calling 5629 `DMCreateLabel`(dm, "celltype") beforehand. 5630 5631 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5632 @*/ 5633 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5634 { 5635 PetscFunctionBegin; 5636 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5637 PetscAssertPointer(celltypeLabel, 2); 5638 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5639 *celltypeLabel = dm->celltypeLabel; 5640 PetscFunctionReturn(PETSC_SUCCESS); 5641 } 5642 5643 /*@ 5644 DMPlexGetCellType - Get the polytope type of a given cell 5645 5646 Not Collective 5647 5648 Input Parameters: 5649 + dm - The `DMPLEX` object 5650 - cell - The cell 5651 5652 Output Parameter: 5653 . celltype - The polytope type of the cell 5654 5655 Level: intermediate 5656 5657 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5658 @*/ 5659 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5660 { 5661 DM_Plex *mesh = (DM_Plex *)dm->data; 5662 DMLabel label; 5663 PetscInt ct; 5664 5665 PetscFunctionBegin; 5666 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5667 PetscAssertPointer(celltype, 3); 5668 if (mesh->tr) { 5669 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5670 } else { 5671 PetscInt pStart, pEnd; 5672 5673 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5674 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5675 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5676 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5677 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5678 for (PetscInt p = pStart; p < pEnd; p++) { 5679 PetscCall(DMLabelGetValue(label, p, &ct)); 5680 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5681 } 5682 } 5683 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5684 if (PetscDefined(USE_DEBUG)) { 5685 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5686 PetscCall(DMLabelGetValue(label, cell, &ct)); 5687 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5688 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5689 } 5690 } 5691 PetscFunctionReturn(PETSC_SUCCESS); 5692 } 5693 5694 /*@ 5695 DMPlexSetCellType - Set the polytope type of a given cell 5696 5697 Not Collective 5698 5699 Input Parameters: 5700 + dm - The `DMPLEX` object 5701 . cell - The cell 5702 - celltype - The polytope type of the cell 5703 5704 Level: advanced 5705 5706 Note: 5707 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5708 is executed. This function will override the computed type. However, if automatic classification will not succeed 5709 and a user wants to manually specify all types, the classification must be disabled by calling 5710 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5711 5712 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5713 @*/ 5714 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5715 { 5716 DM_Plex *mesh = (DM_Plex *)dm->data; 5717 DMLabel label; 5718 PetscInt pStart, pEnd; 5719 5720 PetscFunctionBegin; 5721 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5722 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5723 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5724 PetscCall(DMLabelSetValue(label, cell, celltype)); 5725 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5726 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5727 PetscFunctionReturn(PETSC_SUCCESS); 5728 } 5729 5730 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5731 { 5732 PetscSection section; 5733 PetscInt maxHeight; 5734 const char *prefix; 5735 5736 PetscFunctionBegin; 5737 PetscCall(DMClone(dm, cdm)); 5738 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5739 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5740 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5741 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5742 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5743 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5744 PetscCall(DMSetLocalSection(*cdm, section)); 5745 PetscCall(PetscSectionDestroy(§ion)); 5746 5747 PetscCall(DMSetNumFields(*cdm, 1)); 5748 PetscCall(DMCreateDS(*cdm)); 5749 (*cdm)->cloneOpts = PETSC_TRUE; 5750 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5751 PetscFunctionReturn(PETSC_SUCCESS); 5752 } 5753 5754 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5755 { 5756 Vec coordsLocal, cellCoordsLocal; 5757 DM coordsDM, cellCoordsDM; 5758 5759 PetscFunctionBegin; 5760 *field = NULL; 5761 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5762 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5763 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5764 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5765 if (coordsLocal && coordsDM) { 5766 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5767 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5768 } 5769 PetscFunctionReturn(PETSC_SUCCESS); 5770 } 5771 5772 /*@ 5773 DMPlexGetConeSection - Return a section which describes the layout of cone data 5774 5775 Not Collective 5776 5777 Input Parameter: 5778 . dm - The `DMPLEX` object 5779 5780 Output Parameter: 5781 . section - The `PetscSection` object 5782 5783 Level: developer 5784 5785 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5786 @*/ 5787 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5788 { 5789 DM_Plex *mesh = (DM_Plex *)dm->data; 5790 5791 PetscFunctionBegin; 5792 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5793 if (section) *section = mesh->coneSection; 5794 PetscFunctionReturn(PETSC_SUCCESS); 5795 } 5796 5797 /*@ 5798 DMPlexGetSupportSection - Return a section which describes the layout of support 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`, `DMPlexGetConeSection()`, `PetscSection` 5811 @*/ 5812 PetscErrorCode DMPlexGetSupportSection(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->supportSection; 5819 PetscFunctionReturn(PETSC_SUCCESS); 5820 } 5821 5822 /*@C 5823 DMPlexGetCones - Return cone data 5824 5825 Not Collective 5826 5827 Input Parameter: 5828 . dm - The `DMPLEX` object 5829 5830 Output Parameter: 5831 . cones - The cone for each point 5832 5833 Level: developer 5834 5835 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5836 @*/ 5837 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5838 { 5839 DM_Plex *mesh = (DM_Plex *)dm->data; 5840 5841 PetscFunctionBegin; 5842 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5843 if (cones) *cones = mesh->cones; 5844 PetscFunctionReturn(PETSC_SUCCESS); 5845 } 5846 5847 /*@C 5848 DMPlexGetConeOrientations - Return cone orientation data 5849 5850 Not Collective 5851 5852 Input Parameter: 5853 . dm - The `DMPLEX` object 5854 5855 Output Parameter: 5856 . coneOrientations - The array of cone orientations for all points 5857 5858 Level: developer 5859 5860 Notes: 5861 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5862 as returned by `DMPlexGetConeOrientation()`. 5863 5864 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5865 5866 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5867 @*/ 5868 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5869 { 5870 DM_Plex *mesh = (DM_Plex *)dm->data; 5871 5872 PetscFunctionBegin; 5873 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5874 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5875 PetscFunctionReturn(PETSC_SUCCESS); 5876 } 5877 5878 /* FEM Support */ 5879 5880 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5881 { 5882 PetscInt depth; 5883 5884 PetscFunctionBegin; 5885 PetscCall(DMPlexGetDepth(plex, &depth)); 5886 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5887 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5888 PetscFunctionReturn(PETSC_SUCCESS); 5889 } 5890 5891 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5892 { 5893 PetscInt depth; 5894 5895 PetscFunctionBegin; 5896 PetscCall(DMPlexGetDepth(plex, &depth)); 5897 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5898 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5899 PetscFunctionReturn(PETSC_SUCCESS); 5900 } 5901 5902 /* 5903 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5904 representing a line in the section. 5905 */ 5906 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5907 { 5908 PetscObject obj; 5909 PetscClassId id; 5910 PetscFE fe = NULL; 5911 5912 PetscFunctionBeginHot; 5913 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5914 PetscCall(DMGetField(dm, field, NULL, &obj)); 5915 PetscCall(PetscObjectGetClassId(obj, &id)); 5916 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5917 5918 if (!fe) { 5919 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5920 /* An order k SEM disc has k-1 dofs on an edge */ 5921 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5922 *k = *k / *Nc + 1; 5923 } else { 5924 PetscInt dual_space_size, dim; 5925 PetscDualSpace dsp; 5926 5927 PetscCall(DMGetDimension(dm, &dim)); 5928 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5929 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5930 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5931 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5932 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5933 } 5934 PetscFunctionReturn(PETSC_SUCCESS); 5935 } 5936 5937 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5938 { 5939 PetscFunctionBeginHot; 5940 if (tensor) { 5941 *dof = PetscPowInt(k + 1, dim); 5942 } else { 5943 switch (dim) { 5944 case 1: 5945 *dof = k + 1; 5946 break; 5947 case 2: 5948 *dof = ((k + 1) * (k + 2)) / 2; 5949 break; 5950 case 3: 5951 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5952 break; 5953 default: 5954 *dof = 0; 5955 } 5956 } 5957 PetscFunctionReturn(PETSC_SUCCESS); 5958 } 5959 5960 /*@ 5961 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5962 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5963 section provided (or the section of the `DM`). 5964 5965 Input Parameters: 5966 + dm - The `DM` 5967 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5968 - section - The `PetscSection` to reorder, or `NULL` for the default section 5969 5970 Example: 5971 A typical interpolated single-quad mesh might order points as 5972 .vb 5973 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5974 5975 v4 -- e6 -- v3 5976 | | 5977 e7 c0 e8 5978 | | 5979 v1 -- e5 -- v2 5980 .ve 5981 5982 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5983 dofs in the order of points, e.g., 5984 .vb 5985 c0 -> [0,1,2,3] 5986 v1 -> [4] 5987 ... 5988 e5 -> [8, 9] 5989 .ve 5990 5991 which corresponds to the dofs 5992 .vb 5993 6 10 11 7 5994 13 2 3 15 5995 12 0 1 14 5996 4 8 9 5 5997 .ve 5998 5999 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 6000 .vb 6001 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 6002 .ve 6003 6004 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 6005 .vb 6006 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 6007 .ve 6008 6009 Level: developer 6010 6011 Notes: 6012 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 6013 degree of the basis. 6014 6015 This is required to run with libCEED. 6016 6017 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 6018 @*/ 6019 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 6020 { 6021 DMLabel label; 6022 PetscInt dim, depth = -1, eStart = -1, Nf; 6023 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 6024 6025 PetscFunctionBegin; 6026 PetscCall(DMGetDimension(dm, &dim)); 6027 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 6028 if (point < 0) { 6029 PetscInt sStart, sEnd; 6030 6031 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6032 point = sEnd - sStart ? sStart : point; 6033 } 6034 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6035 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6036 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6037 if (depth == 1) { 6038 eStart = point; 6039 } else if (depth == dim) { 6040 const PetscInt *cone; 6041 6042 PetscCall(DMPlexGetCone(dm, point, &cone)); 6043 if (dim == 2) eStart = cone[0]; 6044 else if (dim == 3) { 6045 const PetscInt *cone2; 6046 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6047 eStart = cone2[0]; 6048 } 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); 6049 } 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); 6050 6051 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6052 for (PetscInt d = 1; d <= dim; d++) { 6053 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6054 PetscInt *perm; 6055 6056 for (f = 0; f < Nf; ++f) { 6057 PetscInt dof; 6058 6059 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6060 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6061 if (!continuous && d < dim) continue; 6062 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6063 size += dof * Nc; 6064 } 6065 PetscCall(PetscMalloc1(size, &perm)); 6066 for (f = 0; f < Nf; ++f) { 6067 switch (d) { 6068 case 1: 6069 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6070 if (!continuous && d < dim) continue; 6071 /* 6072 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6073 We want [ vtx0; edge of length k-1; vtx1 ] 6074 */ 6075 if (continuous) { 6076 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6077 for (i = 0; i < k - 1; i++) 6078 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6079 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6080 foffset = offset; 6081 } else { 6082 PetscInt dof; 6083 6084 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6085 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6086 foffset = offset; 6087 } 6088 break; 6089 case 2: 6090 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6091 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6092 if (!continuous && d < dim) continue; 6093 /* The SEM order is 6094 6095 v_lb, {e_b}, v_rb, 6096 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6097 v_lt, reverse {e_t}, v_rt 6098 */ 6099 if (continuous) { 6100 const PetscInt of = 0; 6101 const PetscInt oeb = of + PetscSqr(k - 1); 6102 const PetscInt oer = oeb + (k - 1); 6103 const PetscInt oet = oer + (k - 1); 6104 const PetscInt oel = oet + (k - 1); 6105 const PetscInt ovlb = oel + (k - 1); 6106 const PetscInt ovrb = ovlb + 1; 6107 const PetscInt ovrt = ovrb + 1; 6108 const PetscInt ovlt = ovrt + 1; 6109 PetscInt o; 6110 6111 /* bottom */ 6112 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6113 for (o = oeb; o < oer; ++o) 6114 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6115 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6116 /* middle */ 6117 for (i = 0; i < k - 1; ++i) { 6118 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6119 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6120 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6121 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6122 } 6123 /* top */ 6124 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6125 for (o = oel - 1; o >= oet; --o) 6126 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6127 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6128 foffset = offset; 6129 } else { 6130 PetscInt dof; 6131 6132 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6133 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6134 foffset = offset; 6135 } 6136 break; 6137 case 3: 6138 /* The original hex closure is 6139 6140 {c, 6141 f_b, f_t, f_f, f_b, f_r, f_l, 6142 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6143 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6144 */ 6145 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6146 if (!continuous && d < dim) continue; 6147 /* The SEM order is 6148 Bottom Slice 6149 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6150 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6151 v_blb, {e_bb}, v_brb, 6152 6153 Middle Slice (j) 6154 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6155 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6156 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6157 6158 Top Slice 6159 v_tlf, {e_tf}, v_trf, 6160 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6161 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6162 */ 6163 if (continuous) { 6164 const PetscInt oc = 0; 6165 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6166 const PetscInt oft = ofb + PetscSqr(k - 1); 6167 const PetscInt off = oft + PetscSqr(k - 1); 6168 const PetscInt ofk = off + PetscSqr(k - 1); 6169 const PetscInt ofr = ofk + PetscSqr(k - 1); 6170 const PetscInt ofl = ofr + PetscSqr(k - 1); 6171 const PetscInt oebl = ofl + PetscSqr(k - 1); 6172 const PetscInt oebb = oebl + (k - 1); 6173 const PetscInt oebr = oebb + (k - 1); 6174 const PetscInt oebf = oebr + (k - 1); 6175 const PetscInt oetf = oebf + (k - 1); 6176 const PetscInt oetr = oetf + (k - 1); 6177 const PetscInt oetb = oetr + (k - 1); 6178 const PetscInt oetl = oetb + (k - 1); 6179 const PetscInt oerf = oetl + (k - 1); 6180 const PetscInt oelf = oerf + (k - 1); 6181 const PetscInt oelb = oelf + (k - 1); 6182 const PetscInt oerb = oelb + (k - 1); 6183 const PetscInt ovblf = oerb + (k - 1); 6184 const PetscInt ovblb = ovblf + 1; 6185 const PetscInt ovbrb = ovblb + 1; 6186 const PetscInt ovbrf = ovbrb + 1; 6187 const PetscInt ovtlf = ovbrf + 1; 6188 const PetscInt ovtrf = ovtlf + 1; 6189 const PetscInt ovtrb = ovtrf + 1; 6190 const PetscInt ovtlb = ovtrb + 1; 6191 PetscInt o, n; 6192 6193 /* Bottom Slice */ 6194 /* bottom */ 6195 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6196 for (o = oetf - 1; o >= oebf; --o) 6197 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6198 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6199 /* middle */ 6200 for (i = 0; i < k - 1; ++i) { 6201 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6202 for (n = 0; n < k - 1; ++n) { 6203 o = ofb + n * (k - 1) + i; 6204 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6205 } 6206 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6207 } 6208 /* top */ 6209 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6210 for (o = oebb; o < oebr; ++o) 6211 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6212 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6213 6214 /* Middle Slice */ 6215 for (j = 0; j < k - 1; ++j) { 6216 /* bottom */ 6217 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6218 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6219 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6220 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6221 /* middle */ 6222 for (i = 0; i < k - 1; ++i) { 6223 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6224 for (n = 0; n < k - 1; ++n) 6225 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6226 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6227 } 6228 /* top */ 6229 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6230 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6231 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6232 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6233 } 6234 6235 /* Top Slice */ 6236 /* bottom */ 6237 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6238 for (o = oetf; o < oetr; ++o) 6239 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6240 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6241 /* middle */ 6242 for (i = 0; i < k - 1; ++i) { 6243 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6244 for (n = 0; n < k - 1; ++n) 6245 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6246 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6247 } 6248 /* top */ 6249 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6250 for (o = oetl - 1; o >= oetb; --o) 6251 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6252 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6253 6254 foffset = offset; 6255 } else { 6256 PetscInt dof; 6257 6258 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6259 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6260 foffset = offset; 6261 } 6262 break; 6263 default: 6264 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6265 } 6266 } 6267 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6268 /* Check permutation */ 6269 { 6270 PetscInt *check; 6271 6272 PetscCall(PetscMalloc1(size, &check)); 6273 for (i = 0; i < size; ++i) { 6274 check[i] = -1; 6275 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6276 } 6277 for (i = 0; i < size; ++i) check[perm[i]] = i; 6278 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6279 PetscCall(PetscFree(check)); 6280 } 6281 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6282 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6283 PetscInt *loc_perm; 6284 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6285 for (PetscInt i = 0; i < size; i++) { 6286 loc_perm[i] = perm[i]; 6287 loc_perm[size + i] = size + perm[i]; 6288 } 6289 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6290 } 6291 } 6292 PetscFunctionReturn(PETSC_SUCCESS); 6293 } 6294 6295 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6296 { 6297 PetscDS prob; 6298 PetscInt depth, Nf, h; 6299 DMLabel label; 6300 6301 PetscFunctionBeginHot; 6302 PetscCall(DMGetDS(dm, &prob)); 6303 Nf = prob->Nf; 6304 label = dm->depthLabel; 6305 *dspace = NULL; 6306 if (field < Nf) { 6307 PetscObject disc = prob->disc[field]; 6308 6309 if (disc->classid == PETSCFE_CLASSID) { 6310 PetscDualSpace dsp; 6311 6312 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6313 PetscCall(DMLabelGetNumValues(label, &depth)); 6314 PetscCall(DMLabelGetValue(label, point, &h)); 6315 h = depth - 1 - h; 6316 if (h) { 6317 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6318 } else { 6319 *dspace = dsp; 6320 } 6321 } 6322 } 6323 PetscFunctionReturn(PETSC_SUCCESS); 6324 } 6325 6326 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6327 { 6328 PetscScalar *array; 6329 const PetscScalar *vArray; 6330 const PetscInt *cone, *coneO; 6331 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6332 6333 PetscFunctionBeginHot; 6334 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6335 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6336 PetscCall(DMPlexGetCone(dm, point, &cone)); 6337 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6338 if (!values || !*values) { 6339 if ((point >= pStart) && (point < pEnd)) { 6340 PetscInt dof; 6341 6342 PetscCall(PetscSectionGetDof(section, point, &dof)); 6343 size += dof; 6344 } 6345 for (p = 0; p < numPoints; ++p) { 6346 const PetscInt cp = cone[p]; 6347 PetscInt dof; 6348 6349 if ((cp < pStart) || (cp >= pEnd)) continue; 6350 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6351 size += dof; 6352 } 6353 if (!values) { 6354 if (csize) *csize = size; 6355 PetscFunctionReturn(PETSC_SUCCESS); 6356 } 6357 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6358 } else { 6359 array = *values; 6360 } 6361 size = 0; 6362 PetscCall(VecGetArrayRead(v, &vArray)); 6363 if ((point >= pStart) && (point < pEnd)) { 6364 PetscInt dof, off, d; 6365 const PetscScalar *varr; 6366 6367 PetscCall(PetscSectionGetDof(section, point, &dof)); 6368 PetscCall(PetscSectionGetOffset(section, point, &off)); 6369 varr = PetscSafePointerPlusOffset(vArray, off); 6370 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6371 size += dof; 6372 } 6373 for (p = 0; p < numPoints; ++p) { 6374 const PetscInt cp = cone[p]; 6375 PetscInt o = coneO[p]; 6376 PetscInt dof, off, d; 6377 const PetscScalar *varr; 6378 6379 if ((cp < pStart) || (cp >= pEnd)) continue; 6380 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6381 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6382 varr = PetscSafePointerPlusOffset(vArray, off); 6383 if (o >= 0) { 6384 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6385 } else { 6386 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6387 } 6388 size += dof; 6389 } 6390 PetscCall(VecRestoreArrayRead(v, &vArray)); 6391 if (!*values) { 6392 if (csize) *csize = size; 6393 *values = array; 6394 } else { 6395 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6396 *csize = size; 6397 } 6398 PetscFunctionReturn(PETSC_SUCCESS); 6399 } 6400 6401 /* Compress out points not in the section */ 6402 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6403 { 6404 const PetscInt np = *numPoints; 6405 PetscInt pStart, pEnd, p, q; 6406 6407 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6408 for (p = 0, q = 0; p < np; ++p) { 6409 const PetscInt r = points[p * 2]; 6410 if ((r >= pStart) && (r < pEnd)) { 6411 points[q * 2] = r; 6412 points[q * 2 + 1] = points[p * 2 + 1]; 6413 ++q; 6414 } 6415 } 6416 *numPoints = q; 6417 return PETSC_SUCCESS; 6418 } 6419 6420 /* Compressed closure does not apply closure permutation */ 6421 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6422 { 6423 const PetscInt *cla = NULL; 6424 PetscInt np, *pts = NULL; 6425 6426 PetscFunctionBeginHot; 6427 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6428 if (!ornt && *clPoints) { 6429 PetscInt dof, off; 6430 6431 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6432 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6433 PetscCall(ISGetIndices(*clPoints, &cla)); 6434 np = dof / 2; 6435 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6436 } else { 6437 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6438 PetscCall(CompressPoints_Private(section, &np, pts)); 6439 } 6440 *numPoints = np; 6441 *points = pts; 6442 *clp = cla; 6443 PetscFunctionReturn(PETSC_SUCCESS); 6444 } 6445 6446 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6447 { 6448 PetscFunctionBeginHot; 6449 if (!*clPoints) { 6450 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6451 } else { 6452 PetscCall(ISRestoreIndices(*clPoints, clp)); 6453 } 6454 *numPoints = 0; 6455 *points = NULL; 6456 *clSec = NULL; 6457 *clPoints = NULL; 6458 *clp = NULL; 6459 PetscFunctionReturn(PETSC_SUCCESS); 6460 } 6461 6462 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6463 { 6464 PetscInt offset = 0, p; 6465 const PetscInt **perms = NULL; 6466 const PetscScalar **flips = NULL; 6467 6468 PetscFunctionBeginHot; 6469 *size = 0; 6470 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6471 for (p = 0; p < numPoints; p++) { 6472 const PetscInt point = points[2 * p]; 6473 const PetscInt *perm = perms ? perms[p] : NULL; 6474 const PetscScalar *flip = flips ? flips[p] : NULL; 6475 PetscInt dof, off, d; 6476 const PetscScalar *varr; 6477 6478 PetscCall(PetscSectionGetDof(section, point, &dof)); 6479 PetscCall(PetscSectionGetOffset(section, point, &off)); 6480 varr = PetscSafePointerPlusOffset(vArray, off); 6481 if (clperm) { 6482 if (perm) { 6483 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6484 } else { 6485 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6486 } 6487 if (flip) { 6488 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6489 } 6490 } else { 6491 if (perm) { 6492 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6493 } else { 6494 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6495 } 6496 if (flip) { 6497 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6498 } 6499 } 6500 offset += dof; 6501 } 6502 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6503 *size = offset; 6504 PetscFunctionReturn(PETSC_SUCCESS); 6505 } 6506 6507 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[]) 6508 { 6509 PetscInt offset = 0, f; 6510 6511 PetscFunctionBeginHot; 6512 *size = 0; 6513 for (f = 0; f < numFields; ++f) { 6514 PetscInt p; 6515 const PetscInt **perms = NULL; 6516 const PetscScalar **flips = NULL; 6517 6518 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6519 for (p = 0; p < numPoints; p++) { 6520 const PetscInt point = points[2 * p]; 6521 PetscInt fdof, foff, b; 6522 const PetscScalar *varr; 6523 const PetscInt *perm = perms ? perms[p] : NULL; 6524 const PetscScalar *flip = flips ? flips[p] : NULL; 6525 6526 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6527 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6528 varr = &vArray[foff]; 6529 if (clperm) { 6530 if (perm) { 6531 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6532 } else { 6533 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6534 } 6535 if (flip) { 6536 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6537 } 6538 } else { 6539 if (perm) { 6540 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6541 } else { 6542 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6543 } 6544 if (flip) { 6545 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6546 } 6547 } 6548 offset += fdof; 6549 } 6550 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6551 } 6552 *size = offset; 6553 PetscFunctionReturn(PETSC_SUCCESS); 6554 } 6555 6556 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6557 { 6558 PetscSection clSection; 6559 IS clPoints; 6560 PetscInt *points = NULL; 6561 const PetscInt *clp, *perm = NULL; 6562 PetscInt depth, numFields, numPoints, asize; 6563 6564 PetscFunctionBeginHot; 6565 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6566 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6567 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6568 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6569 PetscCall(DMPlexGetDepth(dm, &depth)); 6570 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6571 if (depth == 1 && numFields < 2) { 6572 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6573 PetscFunctionReturn(PETSC_SUCCESS); 6574 } 6575 /* Get points */ 6576 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6577 /* Get sizes */ 6578 asize = 0; 6579 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6580 PetscInt dof; 6581 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6582 asize += dof; 6583 } 6584 if (values) { 6585 const PetscScalar *vArray; 6586 PetscInt size; 6587 6588 if (*values) { 6589 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); 6590 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6591 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6592 PetscCall(VecGetArrayRead(v, &vArray)); 6593 /* Get values */ 6594 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6595 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6596 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6597 /* Cleanup array */ 6598 PetscCall(VecRestoreArrayRead(v, &vArray)); 6599 } 6600 if (csize) *csize = asize; 6601 /* Cleanup points */ 6602 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6603 PetscFunctionReturn(PETSC_SUCCESS); 6604 } 6605 6606 /*@C 6607 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6608 6609 Not collective 6610 6611 Input Parameters: 6612 + dm - The `DM` 6613 . section - The section describing the layout in `v`, or `NULL` to use the default section 6614 . v - The local vector 6615 - point - The point in the `DM` 6616 6617 Input/Output Parameters: 6618 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6619 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6620 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6621 6622 Level: intermediate 6623 6624 Notes: 6625 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6626 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6627 assembly function, and a user may already have allocated storage for this operation. 6628 6629 A typical use could be 6630 .vb 6631 values = NULL; 6632 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6633 for (cl = 0; cl < clSize; ++cl) { 6634 <Compute on closure> 6635 } 6636 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6637 .ve 6638 or 6639 .vb 6640 PetscMalloc1(clMaxSize, &values); 6641 for (p = pStart; p < pEnd; ++p) { 6642 clSize = clMaxSize; 6643 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6644 for (cl = 0; cl < clSize; ++cl) { 6645 <Compute on closure> 6646 } 6647 } 6648 PetscFree(values); 6649 .ve 6650 6651 Fortran Notes: 6652 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6653 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6654 6655 `values` must be declared with 6656 .vb 6657 PetscScalar,dimension(:),pointer :: values 6658 .ve 6659 and it will be allocated internally by PETSc to hold the values returned 6660 6661 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6662 @*/ 6663 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6664 { 6665 PetscFunctionBeginHot; 6666 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6667 PetscFunctionReturn(PETSC_SUCCESS); 6668 } 6669 6670 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6671 { 6672 DMLabel depthLabel; 6673 PetscSection clSection; 6674 IS clPoints; 6675 PetscScalar *array; 6676 const PetscScalar *vArray; 6677 PetscInt *points = NULL; 6678 const PetscInt *clp, *perm = NULL; 6679 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6680 6681 PetscFunctionBeginHot; 6682 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6683 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6684 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6685 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6686 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6687 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6688 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6689 if (mdepth == 1 && numFields < 2) { 6690 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6691 PetscFunctionReturn(PETSC_SUCCESS); 6692 } 6693 /* Get points */ 6694 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6695 for (clsize = 0, p = 0; p < Np; p++) { 6696 PetscInt dof; 6697 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6698 clsize += dof; 6699 } 6700 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6701 /* Filter points */ 6702 for (p = 0; p < numPoints * 2; p += 2) { 6703 PetscInt dep; 6704 6705 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6706 if (dep != depth) continue; 6707 points[Np * 2 + 0] = points[p]; 6708 points[Np * 2 + 1] = points[p + 1]; 6709 ++Np; 6710 } 6711 /* Get array */ 6712 if (!values || !*values) { 6713 PetscInt asize = 0, dof; 6714 6715 for (p = 0; p < Np * 2; p += 2) { 6716 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6717 asize += dof; 6718 } 6719 if (!values) { 6720 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6721 if (csize) *csize = asize; 6722 PetscFunctionReturn(PETSC_SUCCESS); 6723 } 6724 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6725 } else { 6726 array = *values; 6727 } 6728 PetscCall(VecGetArrayRead(v, &vArray)); 6729 /* Get values */ 6730 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6731 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6732 /* Cleanup points */ 6733 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6734 /* Cleanup array */ 6735 PetscCall(VecRestoreArrayRead(v, &vArray)); 6736 if (!*values) { 6737 if (csize) *csize = size; 6738 *values = array; 6739 } else { 6740 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6741 *csize = size; 6742 } 6743 PetscFunctionReturn(PETSC_SUCCESS); 6744 } 6745 6746 /*@C 6747 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6748 6749 Not collective 6750 6751 Input Parameters: 6752 + dm - The `DM` 6753 . section - The section describing the layout in `v`, or `NULL` to use the default section 6754 . v - The local vector 6755 . point - The point in the `DM` 6756 . csize - The number of values in the closure, or `NULL` 6757 - values - The array of values 6758 6759 Level: intermediate 6760 6761 Note: 6762 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6763 6764 Fortran Note: 6765 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6766 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6767 6768 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6769 @*/ 6770 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6771 { 6772 PetscInt size = 0; 6773 6774 PetscFunctionBegin; 6775 /* Should work without recalculating size */ 6776 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6777 *values = NULL; 6778 PetscFunctionReturn(PETSC_SUCCESS); 6779 } 6780 6781 static inline void add(PetscScalar *x, PetscScalar y) 6782 { 6783 *x += y; 6784 } 6785 static inline void insert(PetscScalar *x, PetscScalar y) 6786 { 6787 *x = y; 6788 } 6789 6790 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[]) 6791 { 6792 PetscInt cdof; /* The number of constraints on this point */ 6793 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6794 PetscScalar *a; 6795 PetscInt off, cind = 0, k; 6796 6797 PetscFunctionBegin; 6798 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6799 PetscCall(PetscSectionGetOffset(section, point, &off)); 6800 a = &array[off]; 6801 if (!cdof || setBC) { 6802 if (clperm) { 6803 if (perm) { 6804 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6805 } else { 6806 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6807 } 6808 } else { 6809 if (perm) { 6810 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6811 } else { 6812 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6813 } 6814 } 6815 } else { 6816 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6817 if (clperm) { 6818 if (perm) { 6819 for (k = 0; k < dof; ++k) { 6820 if ((cind < cdof) && (k == cdofs[cind])) { 6821 ++cind; 6822 continue; 6823 } 6824 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6825 } 6826 } else { 6827 for (k = 0; k < dof; ++k) { 6828 if ((cind < cdof) && (k == cdofs[cind])) { 6829 ++cind; 6830 continue; 6831 } 6832 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6833 } 6834 } 6835 } else { 6836 if (perm) { 6837 for (k = 0; k < dof; ++k) { 6838 if ((cind < cdof) && (k == cdofs[cind])) { 6839 ++cind; 6840 continue; 6841 } 6842 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6843 } 6844 } else { 6845 for (k = 0; k < dof; ++k) { 6846 if ((cind < cdof) && (k == cdofs[cind])) { 6847 ++cind; 6848 continue; 6849 } 6850 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6851 } 6852 } 6853 } 6854 } 6855 PetscFunctionReturn(PETSC_SUCCESS); 6856 } 6857 6858 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[]) 6859 { 6860 PetscInt cdof; /* The number of constraints on this point */ 6861 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6862 PetscScalar *a; 6863 PetscInt off, cind = 0, k; 6864 6865 PetscFunctionBegin; 6866 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6867 PetscCall(PetscSectionGetOffset(section, point, &off)); 6868 a = &array[off]; 6869 if (cdof) { 6870 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6871 if (clperm) { 6872 if (perm) { 6873 for (k = 0; k < dof; ++k) { 6874 if ((cind < cdof) && (k == cdofs[cind])) { 6875 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6876 cind++; 6877 } 6878 } 6879 } else { 6880 for (k = 0; k < dof; ++k) { 6881 if ((cind < cdof) && (k == cdofs[cind])) { 6882 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6883 cind++; 6884 } 6885 } 6886 } 6887 } else { 6888 if (perm) { 6889 for (k = 0; k < dof; ++k) { 6890 if ((cind < cdof) && (k == cdofs[cind])) { 6891 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6892 cind++; 6893 } 6894 } 6895 } else { 6896 for (k = 0; k < dof; ++k) { 6897 if ((cind < cdof) && (k == cdofs[cind])) { 6898 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6899 cind++; 6900 } 6901 } 6902 } 6903 } 6904 } 6905 PetscFunctionReturn(PETSC_SUCCESS); 6906 } 6907 6908 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[]) 6909 { 6910 PetscScalar *a; 6911 PetscInt fdof, foff, fcdof, foffset = *offset; 6912 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6913 PetscInt cind = 0, b; 6914 6915 PetscFunctionBegin; 6916 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6917 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6918 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6919 a = &array[foff]; 6920 if (!fcdof || setBC) { 6921 if (clperm) { 6922 if (perm) { 6923 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6924 } else { 6925 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6926 } 6927 } else { 6928 if (perm) { 6929 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6930 } else { 6931 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6932 } 6933 } 6934 } else { 6935 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6936 if (clperm) { 6937 if (perm) { 6938 for (b = 0; b < fdof; b++) { 6939 if ((cind < fcdof) && (b == fcdofs[cind])) { 6940 ++cind; 6941 continue; 6942 } 6943 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6944 } 6945 } else { 6946 for (b = 0; b < fdof; b++) { 6947 if ((cind < fcdof) && (b == fcdofs[cind])) { 6948 ++cind; 6949 continue; 6950 } 6951 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6952 } 6953 } 6954 } else { 6955 if (perm) { 6956 for (b = 0; b < fdof; b++) { 6957 if ((cind < fcdof) && (b == fcdofs[cind])) { 6958 ++cind; 6959 continue; 6960 } 6961 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6962 } 6963 } else { 6964 for (b = 0; b < fdof; b++) { 6965 if ((cind < fcdof) && (b == fcdofs[cind])) { 6966 ++cind; 6967 continue; 6968 } 6969 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6970 } 6971 } 6972 } 6973 } 6974 *offset += fdof; 6975 PetscFunctionReturn(PETSC_SUCCESS); 6976 } 6977 6978 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[]) 6979 { 6980 PetscScalar *a; 6981 PetscInt fdof, foff, fcdof, foffset = *offset; 6982 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6983 PetscInt Nc, cind = 0, ncind = 0, b; 6984 PetscBool ncSet, fcSet; 6985 6986 PetscFunctionBegin; 6987 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6988 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6989 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6990 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6991 a = &array[foff]; 6992 if (fcdof) { 6993 /* We just override fcdof and fcdofs with Ncc and comps */ 6994 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6995 if (clperm) { 6996 if (perm) { 6997 if (comps) { 6998 for (b = 0; b < fdof; b++) { 6999 ncSet = fcSet = PETSC_FALSE; 7000 if (b % Nc == comps[ncind]) { 7001 ncind = (ncind + 1) % Ncc; 7002 ncSet = PETSC_TRUE; 7003 } 7004 if ((cind < fcdof) && (b == fcdofs[cind])) { 7005 ++cind; 7006 fcSet = PETSC_TRUE; 7007 } 7008 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7009 } 7010 } else { 7011 for (b = 0; b < fdof; b++) { 7012 if ((cind < fcdof) && (b == fcdofs[cind])) { 7013 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7014 ++cind; 7015 } 7016 } 7017 } 7018 } else { 7019 if (comps) { 7020 for (b = 0; b < fdof; b++) { 7021 ncSet = fcSet = PETSC_FALSE; 7022 if (b % Nc == comps[ncind]) { 7023 ncind = (ncind + 1) % Ncc; 7024 ncSet = PETSC_TRUE; 7025 } 7026 if ((cind < fcdof) && (b == fcdofs[cind])) { 7027 ++cind; 7028 fcSet = PETSC_TRUE; 7029 } 7030 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7031 } 7032 } else { 7033 for (b = 0; b < fdof; b++) { 7034 if ((cind < fcdof) && (b == fcdofs[cind])) { 7035 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7036 ++cind; 7037 } 7038 } 7039 } 7040 } 7041 } else { 7042 if (perm) { 7043 if (comps) { 7044 for (b = 0; b < fdof; b++) { 7045 ncSet = fcSet = PETSC_FALSE; 7046 if (b % Nc == comps[ncind]) { 7047 ncind = (ncind + 1) % Ncc; 7048 ncSet = PETSC_TRUE; 7049 } 7050 if ((cind < fcdof) && (b == fcdofs[cind])) { 7051 ++cind; 7052 fcSet = PETSC_TRUE; 7053 } 7054 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7055 } 7056 } else { 7057 for (b = 0; b < fdof; b++) { 7058 if ((cind < fcdof) && (b == fcdofs[cind])) { 7059 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7060 ++cind; 7061 } 7062 } 7063 } 7064 } else { 7065 if (comps) { 7066 for (b = 0; b < fdof; b++) { 7067 ncSet = fcSet = PETSC_FALSE; 7068 if (b % Nc == comps[ncind]) { 7069 ncind = (ncind + 1) % Ncc; 7070 ncSet = PETSC_TRUE; 7071 } 7072 if ((cind < fcdof) && (b == fcdofs[cind])) { 7073 ++cind; 7074 fcSet = PETSC_TRUE; 7075 } 7076 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7077 } 7078 } else { 7079 for (b = 0; b < fdof; b++) { 7080 if ((cind < fcdof) && (b == fcdofs[cind])) { 7081 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7082 ++cind; 7083 } 7084 } 7085 } 7086 } 7087 } 7088 } 7089 *offset += fdof; 7090 PetscFunctionReturn(PETSC_SUCCESS); 7091 } 7092 7093 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7094 { 7095 PetscScalar *array; 7096 const PetscInt *cone, *coneO; 7097 PetscInt pStart, pEnd, p, numPoints, off, dof; 7098 7099 PetscFunctionBeginHot; 7100 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7101 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7102 PetscCall(DMPlexGetCone(dm, point, &cone)); 7103 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7104 PetscCall(VecGetArray(v, &array)); 7105 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7106 const PetscInt cp = !p ? point : cone[p - 1]; 7107 const PetscInt o = !p ? 0 : coneO[p - 1]; 7108 7109 if ((cp < pStart) || (cp >= pEnd)) { 7110 dof = 0; 7111 continue; 7112 } 7113 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7114 /* ADD_VALUES */ 7115 { 7116 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7117 PetscScalar *a; 7118 PetscInt cdof, coff, cind = 0, k; 7119 7120 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7121 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7122 a = &array[coff]; 7123 if (!cdof) { 7124 if (o >= 0) { 7125 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7126 } else { 7127 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7128 } 7129 } else { 7130 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7131 if (o >= 0) { 7132 for (k = 0; k < dof; ++k) { 7133 if ((cind < cdof) && (k == cdofs[cind])) { 7134 ++cind; 7135 continue; 7136 } 7137 a[k] += values[off + k]; 7138 } 7139 } else { 7140 for (k = 0; k < dof; ++k) { 7141 if ((cind < cdof) && (k == cdofs[cind])) { 7142 ++cind; 7143 continue; 7144 } 7145 a[k] += values[off + dof - k - 1]; 7146 } 7147 } 7148 } 7149 } 7150 } 7151 PetscCall(VecRestoreArray(v, &array)); 7152 PetscFunctionReturn(PETSC_SUCCESS); 7153 } 7154 7155 /*@C 7156 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7157 7158 Not collective 7159 7160 Input Parameters: 7161 + dm - The `DM` 7162 . section - The section describing the layout in `v`, or `NULL` to use the default section 7163 . v - The local vector 7164 . point - The point in the `DM` 7165 . values - The array of values 7166 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7167 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7168 7169 Level: intermediate 7170 7171 Note: 7172 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7173 7174 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7175 @*/ 7176 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7177 { 7178 PetscSection clSection; 7179 IS clPoints; 7180 PetscScalar *array; 7181 PetscInt *points = NULL; 7182 const PetscInt *clp, *clperm = NULL; 7183 PetscInt depth, numFields, numPoints, p, clsize; 7184 7185 PetscFunctionBeginHot; 7186 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7187 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7188 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7189 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7190 PetscCall(DMPlexGetDepth(dm, &depth)); 7191 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7192 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7193 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7194 PetscFunctionReturn(PETSC_SUCCESS); 7195 } 7196 /* Get points */ 7197 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7198 for (clsize = 0, p = 0; p < numPoints; p++) { 7199 PetscInt dof; 7200 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7201 clsize += dof; 7202 } 7203 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7204 /* Get array */ 7205 PetscCall(VecGetArray(v, &array)); 7206 /* Get values */ 7207 if (numFields > 0) { 7208 PetscInt offset = 0, f; 7209 for (f = 0; f < numFields; ++f) { 7210 const PetscInt **perms = NULL; 7211 const PetscScalar **flips = NULL; 7212 7213 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7214 switch (mode) { 7215 case INSERT_VALUES: 7216 for (p = 0; p < numPoints; p++) { 7217 const PetscInt point = points[2 * p]; 7218 const PetscInt *perm = perms ? perms[p] : NULL; 7219 const PetscScalar *flip = flips ? flips[p] : NULL; 7220 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7221 } 7222 break; 7223 case INSERT_ALL_VALUES: 7224 for (p = 0; p < numPoints; p++) { 7225 const PetscInt point = points[2 * p]; 7226 const PetscInt *perm = perms ? perms[p] : NULL; 7227 const PetscScalar *flip = flips ? flips[p] : NULL; 7228 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7229 } 7230 break; 7231 case INSERT_BC_VALUES: 7232 for (p = 0; p < numPoints; p++) { 7233 const PetscInt point = points[2 * p]; 7234 const PetscInt *perm = perms ? perms[p] : NULL; 7235 const PetscScalar *flip = flips ? flips[p] : NULL; 7236 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7237 } 7238 break; 7239 case ADD_VALUES: 7240 for (p = 0; p < numPoints; p++) { 7241 const PetscInt point = points[2 * p]; 7242 const PetscInt *perm = perms ? perms[p] : NULL; 7243 const PetscScalar *flip = flips ? flips[p] : NULL; 7244 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7245 } 7246 break; 7247 case ADD_ALL_VALUES: 7248 for (p = 0; p < numPoints; p++) { 7249 const PetscInt point = points[2 * p]; 7250 const PetscInt *perm = perms ? perms[p] : NULL; 7251 const PetscScalar *flip = flips ? flips[p] : NULL; 7252 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7253 } 7254 break; 7255 case ADD_BC_VALUES: 7256 for (p = 0; p < numPoints; p++) { 7257 const PetscInt point = points[2 * p]; 7258 const PetscInt *perm = perms ? perms[p] : NULL; 7259 const PetscScalar *flip = flips ? flips[p] : NULL; 7260 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7261 } 7262 break; 7263 default: 7264 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7265 } 7266 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7267 } 7268 } else { 7269 PetscInt dof, off; 7270 const PetscInt **perms = NULL; 7271 const PetscScalar **flips = NULL; 7272 7273 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7274 switch (mode) { 7275 case INSERT_VALUES: 7276 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7277 const PetscInt point = points[2 * p]; 7278 const PetscInt *perm = perms ? perms[p] : NULL; 7279 const PetscScalar *flip = flips ? flips[p] : NULL; 7280 PetscCall(PetscSectionGetDof(section, point, &dof)); 7281 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7282 } 7283 break; 7284 case INSERT_ALL_VALUES: 7285 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7286 const PetscInt point = points[2 * p]; 7287 const PetscInt *perm = perms ? perms[p] : NULL; 7288 const PetscScalar *flip = flips ? flips[p] : NULL; 7289 PetscCall(PetscSectionGetDof(section, point, &dof)); 7290 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7291 } 7292 break; 7293 case INSERT_BC_VALUES: 7294 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7295 const PetscInt point = points[2 * p]; 7296 const PetscInt *perm = perms ? perms[p] : NULL; 7297 const PetscScalar *flip = flips ? flips[p] : NULL; 7298 PetscCall(PetscSectionGetDof(section, point, &dof)); 7299 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7300 } 7301 break; 7302 case ADD_VALUES: 7303 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7304 const PetscInt point = points[2 * p]; 7305 const PetscInt *perm = perms ? perms[p] : NULL; 7306 const PetscScalar *flip = flips ? flips[p] : NULL; 7307 PetscCall(PetscSectionGetDof(section, point, &dof)); 7308 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7309 } 7310 break; 7311 case ADD_ALL_VALUES: 7312 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7313 const PetscInt point = points[2 * p]; 7314 const PetscInt *perm = perms ? perms[p] : NULL; 7315 const PetscScalar *flip = flips ? flips[p] : NULL; 7316 PetscCall(PetscSectionGetDof(section, point, &dof)); 7317 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7318 } 7319 break; 7320 case ADD_BC_VALUES: 7321 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7322 const PetscInt point = points[2 * p]; 7323 const PetscInt *perm = perms ? perms[p] : NULL; 7324 const PetscScalar *flip = flips ? flips[p] : NULL; 7325 PetscCall(PetscSectionGetDof(section, point, &dof)); 7326 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7327 } 7328 break; 7329 default: 7330 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7331 } 7332 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7333 } 7334 /* Cleanup points */ 7335 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7336 /* Cleanup array */ 7337 PetscCall(VecRestoreArray(v, &array)); 7338 PetscFunctionReturn(PETSC_SUCCESS); 7339 } 7340 7341 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7342 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7343 { 7344 PetscFunctionBegin; 7345 *contains = PETSC_TRUE; 7346 if (label) { 7347 PetscInt fdof; 7348 7349 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7350 if (!*contains) { 7351 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7352 *offset += fdof; 7353 PetscFunctionReturn(PETSC_SUCCESS); 7354 } 7355 } 7356 PetscFunctionReturn(PETSC_SUCCESS); 7357 } 7358 7359 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7360 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) 7361 { 7362 PetscSection clSection; 7363 IS clPoints; 7364 PetscScalar *array; 7365 PetscInt *points = NULL; 7366 const PetscInt *clp; 7367 PetscInt numFields, numPoints, p; 7368 PetscInt offset = 0, f; 7369 7370 PetscFunctionBeginHot; 7371 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7372 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7373 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7374 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7375 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7376 /* Get points */ 7377 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7378 /* Get array */ 7379 PetscCall(VecGetArray(v, &array)); 7380 /* Get values */ 7381 for (f = 0; f < numFields; ++f) { 7382 const PetscInt **perms = NULL; 7383 const PetscScalar **flips = NULL; 7384 PetscBool contains; 7385 7386 if (!fieldActive[f]) { 7387 for (p = 0; p < numPoints * 2; p += 2) { 7388 PetscInt fdof; 7389 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7390 offset += fdof; 7391 } 7392 continue; 7393 } 7394 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7395 switch (mode) { 7396 case INSERT_VALUES: 7397 for (p = 0; p < numPoints; p++) { 7398 const PetscInt point = points[2 * p]; 7399 const PetscInt *perm = perms ? perms[p] : NULL; 7400 const PetscScalar *flip = flips ? flips[p] : NULL; 7401 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7402 if (!contains) continue; 7403 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7404 } 7405 break; 7406 case INSERT_ALL_VALUES: 7407 for (p = 0; p < numPoints; p++) { 7408 const PetscInt point = points[2 * p]; 7409 const PetscInt *perm = perms ? perms[p] : NULL; 7410 const PetscScalar *flip = flips ? flips[p] : NULL; 7411 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7412 if (!contains) continue; 7413 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7414 } 7415 break; 7416 case INSERT_BC_VALUES: 7417 for (p = 0; p < numPoints; p++) { 7418 const PetscInt point = points[2 * p]; 7419 const PetscInt *perm = perms ? perms[p] : NULL; 7420 const PetscScalar *flip = flips ? flips[p] : NULL; 7421 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7422 if (!contains) continue; 7423 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7424 } 7425 break; 7426 case ADD_VALUES: 7427 for (p = 0; p < numPoints; p++) { 7428 const PetscInt point = points[2 * p]; 7429 const PetscInt *perm = perms ? perms[p] : NULL; 7430 const PetscScalar *flip = flips ? flips[p] : NULL; 7431 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7432 if (!contains) continue; 7433 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7434 } 7435 break; 7436 case ADD_ALL_VALUES: 7437 for (p = 0; p < numPoints; p++) { 7438 const PetscInt point = points[2 * p]; 7439 const PetscInt *perm = perms ? perms[p] : NULL; 7440 const PetscScalar *flip = flips ? flips[p] : NULL; 7441 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7442 if (!contains) continue; 7443 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7444 } 7445 break; 7446 default: 7447 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7448 } 7449 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7450 } 7451 /* Cleanup points */ 7452 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7453 /* Cleanup array */ 7454 PetscCall(VecRestoreArray(v, &array)); 7455 PetscFunctionReturn(PETSC_SUCCESS); 7456 } 7457 7458 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7459 { 7460 PetscMPIInt rank; 7461 PetscInt i, j; 7462 7463 PetscFunctionBegin; 7464 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7465 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7466 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7467 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7468 numCIndices = numCIndices ? numCIndices : numRIndices; 7469 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7470 for (i = 0; i < numRIndices; i++) { 7471 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7472 for (j = 0; j < numCIndices; j++) { 7473 #if defined(PETSC_USE_COMPLEX) 7474 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7475 #else 7476 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7477 #endif 7478 } 7479 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7480 } 7481 PetscFunctionReturn(PETSC_SUCCESS); 7482 } 7483 7484 /* 7485 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7486 7487 Input Parameters: 7488 + section - The section for this data layout 7489 . islocal - Is the section (and thus indices being requested) local or global? 7490 . point - The point contributing dofs with these indices 7491 . off - The global offset of this point 7492 . loff - The local offset of each field 7493 . setBC - The flag determining whether to include indices of boundary values 7494 . perm - A permutation of the dofs on this point, or NULL 7495 - indperm - A permutation of the entire indices array, or NULL 7496 7497 Output Parameter: 7498 . indices - Indices for dofs on this point 7499 7500 Level: developer 7501 7502 Note: The indices could be local or global, depending on the value of 'off'. 7503 */ 7504 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7505 { 7506 PetscInt dof; /* The number of unknowns on this point */ 7507 PetscInt cdof; /* The number of constraints on this point */ 7508 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7509 PetscInt cind = 0, k; 7510 7511 PetscFunctionBegin; 7512 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7513 PetscCall(PetscSectionGetDof(section, point, &dof)); 7514 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7515 if (!cdof || setBC) { 7516 for (k = 0; k < dof; ++k) { 7517 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7518 const PetscInt ind = indperm ? indperm[preind] : preind; 7519 7520 indices[ind] = off + k; 7521 } 7522 } else { 7523 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7524 for (k = 0; k < dof; ++k) { 7525 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7526 const PetscInt ind = indperm ? indperm[preind] : preind; 7527 7528 if ((cind < cdof) && (k == cdofs[cind])) { 7529 /* Insert check for returning constrained indices */ 7530 indices[ind] = -(off + k + 1); 7531 ++cind; 7532 } else { 7533 indices[ind] = off + k - (islocal ? 0 : cind); 7534 } 7535 } 7536 } 7537 *loff += dof; 7538 PetscFunctionReturn(PETSC_SUCCESS); 7539 } 7540 7541 /* 7542 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7543 7544 Input Parameters: 7545 + section - a section (global or local) 7546 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7547 . point - point within section 7548 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7549 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7550 . setBC - identify constrained (boundary condition) points via involution. 7551 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7552 . permsoff - offset 7553 - indperm - index permutation 7554 7555 Output Parameter: 7556 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7557 . indices - array to hold indices (as defined by section) of each dof associated with point 7558 7559 Notes: 7560 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7561 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7562 in the local vector. 7563 7564 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7565 significant). It is invalid to call with a global section and setBC=true. 7566 7567 Developer Note: 7568 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7569 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7570 offset could be obtained from the section instead of passing it explicitly as we do now. 7571 7572 Example: 7573 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7574 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7575 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7576 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. 7577 7578 Level: developer 7579 */ 7580 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[]) 7581 { 7582 PetscInt numFields, foff, f; 7583 7584 PetscFunctionBegin; 7585 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7586 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7587 for (f = 0, foff = 0; f < numFields; ++f) { 7588 PetscInt fdof, cfdof; 7589 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7590 PetscInt cind = 0, b; 7591 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7592 7593 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7594 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7595 if (!cfdof || setBC) { 7596 for (b = 0; b < fdof; ++b) { 7597 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7598 const PetscInt ind = indperm ? indperm[preind] : preind; 7599 7600 indices[ind] = off + foff + b; 7601 } 7602 } else { 7603 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7604 for (b = 0; b < fdof; ++b) { 7605 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7606 const PetscInt ind = indperm ? indperm[preind] : preind; 7607 7608 if ((cind < cfdof) && (b == fcdofs[cind])) { 7609 indices[ind] = -(off + foff + b + 1); 7610 ++cind; 7611 } else { 7612 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7613 } 7614 } 7615 } 7616 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7617 foffs[f] += fdof; 7618 } 7619 PetscFunctionReturn(PETSC_SUCCESS); 7620 } 7621 7622 /* 7623 This version believes the globalSection offsets for each field, rather than just the point offset 7624 7625 . foffs - The offset into 'indices' for each field, since it is segregated by field 7626 7627 Notes: 7628 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7629 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7630 */ 7631 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7632 { 7633 PetscInt numFields, foff, f; 7634 7635 PetscFunctionBegin; 7636 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7637 for (f = 0; f < numFields; ++f) { 7638 PetscInt fdof, cfdof; 7639 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7640 PetscInt cind = 0, b; 7641 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7642 7643 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7644 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7645 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7646 if (!cfdof) { 7647 for (b = 0; b < fdof; ++b) { 7648 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7649 const PetscInt ind = indperm ? indperm[preind] : preind; 7650 7651 indices[ind] = foff + b; 7652 } 7653 } else { 7654 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7655 for (b = 0; b < fdof; ++b) { 7656 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7657 const PetscInt ind = indperm ? indperm[preind] : preind; 7658 7659 if ((cind < cfdof) && (b == fcdofs[cind])) { 7660 indices[ind] = -(foff + b + 1); 7661 ++cind; 7662 } else { 7663 indices[ind] = foff + b - cind; 7664 } 7665 } 7666 } 7667 foffs[f] += fdof; 7668 } 7669 PetscFunctionReturn(PETSC_SUCCESS); 7670 } 7671 7672 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7673 { 7674 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7675 7676 PetscFunctionBegin; 7677 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7678 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7679 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7680 for (PetscInt p = 0; p < nPoints; p++) { 7681 PetscInt b = pnts[2 * p]; 7682 PetscInt bSecDof = 0, bOff; 7683 PetscInt cSecDof = 0; 7684 PetscSection indices_section; 7685 7686 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7687 if (!bSecDof) continue; 7688 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7689 indices_section = cSecDof > 0 ? cSec : section; 7690 if (numFields) { 7691 PetscInt fStart[32], fEnd[32]; 7692 7693 fStart[0] = 0; 7694 fEnd[0] = 0; 7695 for (PetscInt f = 0; f < numFields; f++) { 7696 PetscInt fDof = 0; 7697 7698 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7699 fStart[f + 1] = fStart[f] + fDof; 7700 fEnd[f + 1] = fStart[f + 1]; 7701 } 7702 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7703 // only apply permutations on one side 7704 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7705 for (PetscInt f = 0; f < numFields; f++) { 7706 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7707 } 7708 } else { 7709 PetscInt bEnd = 0; 7710 7711 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7712 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7713 7714 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7715 } 7716 } 7717 PetscFunctionReturn(PETSC_SUCCESS); 7718 } 7719 7720 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[]) 7721 { 7722 Mat cMat; 7723 PetscSection aSec, cSec; 7724 IS aIS; 7725 PetscInt aStart = -1, aEnd = -1; 7726 PetscInt sStart = -1, sEnd = -1; 7727 PetscInt cStart = -1, cEnd = -1; 7728 const PetscInt *anchors; 7729 PetscInt numFields, p; 7730 PetscInt newNumPoints = 0, newNumIndices = 0; 7731 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7732 PetscInt oldOffsets[32]; 7733 PetscInt newOffsets[32]; 7734 PetscInt oldOffsetsCopy[32]; 7735 PetscInt newOffsetsCopy[32]; 7736 PetscScalar *modMat = NULL; 7737 PetscBool anyConstrained = PETSC_FALSE; 7738 7739 PetscFunctionBegin; 7740 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7741 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7742 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7743 7744 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7745 /* if there are point-to-point constraints */ 7746 if (aSec) { 7747 PetscCall(PetscArrayzero(newOffsets, 32)); 7748 PetscCall(PetscArrayzero(oldOffsets, 32)); 7749 PetscCall(ISGetIndices(aIS, &anchors)); 7750 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7751 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7752 /* figure out how many points are going to be in the new element matrix 7753 * (we allow double counting, because it's all just going to be summed 7754 * into the global matrix anyway) */ 7755 for (p = 0; p < 2 * numPoints; p += 2) { 7756 PetscInt b = points[p]; 7757 PetscInt bDof = 0, bSecDof = 0; 7758 7759 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7760 if (!bSecDof) continue; 7761 7762 for (PetscInt f = 0; f < numFields; f++) { 7763 PetscInt fDof = 0; 7764 7765 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7766 oldOffsets[f + 1] += fDof; 7767 } 7768 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7769 if (bDof) { 7770 /* this point is constrained */ 7771 /* it is going to be replaced by its anchors */ 7772 PetscInt bOff, q; 7773 7774 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7775 for (q = 0; q < bDof; q++) { 7776 PetscInt a = anchors[bOff + q]; 7777 PetscInt aDof = 0; 7778 7779 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7780 if (aDof) { 7781 anyConstrained = PETSC_TRUE; 7782 newNumPoints += 1; 7783 } 7784 newNumIndices += aDof; 7785 for (PetscInt f = 0; f < numFields; ++f) { 7786 PetscInt fDof = 0; 7787 7788 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7789 newOffsets[f + 1] += fDof; 7790 } 7791 } 7792 } else { 7793 /* this point is not constrained */ 7794 newNumPoints++; 7795 newNumIndices += bSecDof; 7796 for (PetscInt f = 0; f < numFields; ++f) { 7797 PetscInt fDof; 7798 7799 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7800 newOffsets[f + 1] += fDof; 7801 } 7802 } 7803 } 7804 } 7805 if (!anyConstrained) { 7806 if (outNumPoints) *outNumPoints = 0; 7807 if (outNumIndices) *outNumIndices = 0; 7808 if (outPoints) *outPoints = NULL; 7809 if (outMat) *outMat = NULL; 7810 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7811 PetscFunctionReturn(PETSC_SUCCESS); 7812 } 7813 7814 if (outNumPoints) *outNumPoints = newNumPoints; 7815 if (outNumIndices) *outNumIndices = newNumIndices; 7816 7817 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7818 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7819 7820 if (!outPoints && !outMat) { 7821 if (offsets) { 7822 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7823 } 7824 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7825 PetscFunctionReturn(PETSC_SUCCESS); 7826 } 7827 7828 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7829 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7830 7831 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7832 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7833 7834 /* output arrays */ 7835 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7836 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7837 7838 // get the new Points 7839 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7840 PetscInt b = points[2 * p]; 7841 PetscInt bDof = 0, bSecDof = 0, bOff; 7842 7843 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7844 if (!bSecDof) continue; 7845 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7846 if (bDof) { 7847 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7848 for (PetscInt q = 0; q < bDof; q++) { 7849 PetscInt a = anchors[bOff + q], aDof = 0; 7850 7851 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7852 if (aDof) { 7853 newPoints[2 * newP] = a; 7854 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7855 newP++; 7856 } 7857 } 7858 } else { 7859 newPoints[2 * newP] = b; 7860 newPoints[2 * newP + 1] = points[2 * p + 1]; 7861 newP++; 7862 } 7863 } 7864 7865 if (outMat) { 7866 PetscScalar *tmpMat; 7867 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7868 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7869 7870 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7871 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7872 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7873 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7874 7875 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7876 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7877 7878 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7879 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7880 7881 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7882 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7883 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7884 // for each field, insert the anchor modification into modMat 7885 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7886 PetscInt fStart = oldOffsets[f]; 7887 PetscInt fNewStart = newOffsets[f]; 7888 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7889 PetscInt b = points[2 * p]; 7890 PetscInt bDof = 0, bSecDof = 0, bOff; 7891 7892 if (b >= sStart && b < sEnd) { 7893 if (numFields) { 7894 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7895 } else { 7896 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7897 } 7898 } 7899 if (!bSecDof) continue; 7900 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7901 if (bDof) { 7902 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7903 for (PetscInt q = 0; q < bDof; q++, newP++) { 7904 PetscInt a = anchors[bOff + q], aDof = 0; 7905 7906 if (a >= sStart && a < sEnd) { 7907 if (numFields) { 7908 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7909 } else { 7910 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7911 } 7912 } 7913 if (aDof) { 7914 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7915 for (PetscInt d = 0; d < bSecDof; d++) { 7916 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7917 } 7918 } 7919 oNew += aDof; 7920 } 7921 } else { 7922 // Insert the identity matrix in this block 7923 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7924 oNew += bSecDof; 7925 newP++; 7926 } 7927 o += bSecDof; 7928 } 7929 } 7930 7931 *outMat = modMat; 7932 7933 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7934 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7935 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7936 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7937 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7938 } 7939 PetscCall(ISRestoreIndices(aIS, &anchors)); 7940 7941 /* output */ 7942 if (outPoints) { 7943 *outPoints = newPoints; 7944 } else { 7945 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7946 } 7947 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7948 PetscFunctionReturn(PETSC_SUCCESS); 7949 } 7950 7951 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) 7952 { 7953 PetscScalar *modMat = NULL; 7954 PetscInt newNumIndices = -1; 7955 7956 PetscFunctionBegin; 7957 /* 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. 7958 modMat is that matrix C */ 7959 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7960 if (outNumIndices) *outNumIndices = newNumIndices; 7961 if (modMat) { 7962 const PetscScalar *newValues = values; 7963 7964 if (multiplyRight) { 7965 PetscScalar *newNewValues = NULL; 7966 PetscBLASInt M, N, K; 7967 PetscScalar a = 1.0, b = 0.0; 7968 7969 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); 7970 7971 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7972 PetscCall(PetscBLASIntCast(numRows, &N)); 7973 PetscCall(PetscBLASIntCast(numIndices, &K)); 7974 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7975 // row-major to column-major conversion, right multiplication becomes left multiplication 7976 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7977 numCols = newNumIndices; 7978 newValues = newNewValues; 7979 } 7980 7981 if (multiplyLeft) { 7982 PetscScalar *newNewValues = NULL; 7983 PetscBLASInt M, N, K; 7984 PetscScalar a = 1.0, b = 0.0; 7985 7986 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); 7987 7988 PetscCall(PetscBLASIntCast(numCols, &M)); 7989 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7990 PetscCall(PetscBLASIntCast(numIndices, &K)); 7991 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7992 // row-major to column-major conversion, left multiplication becomes right multiplication 7993 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7994 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7995 newValues = newNewValues; 7996 } 7997 *outValues = (PetscScalar *)newValues; 7998 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7999 } 8000 PetscFunctionReturn(PETSC_SUCCESS); 8001 } 8002 8003 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) 8004 { 8005 PetscFunctionBegin; 8006 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 8007 PetscFunctionReturn(PETSC_SUCCESS); 8008 } 8009 8010 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 8011 { 8012 /* Closure ordering */ 8013 PetscSection clSection; 8014 IS clPoints; 8015 const PetscInt *clp; 8016 PetscInt *points; 8017 PetscInt Ncl, Ni = 0; 8018 8019 PetscFunctionBeginHot; 8020 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8021 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 8022 PetscInt dof; 8023 8024 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8025 Ni += dof; 8026 } 8027 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8028 *closureSize = Ni; 8029 PetscFunctionReturn(PETSC_SUCCESS); 8030 } 8031 8032 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) 8033 { 8034 /* Closure ordering */ 8035 PetscSection clSection; 8036 IS clPoints; 8037 const PetscInt *clp; 8038 PetscInt *points; 8039 const PetscInt *clperm = NULL; 8040 /* Dof permutation and sign flips */ 8041 const PetscInt **perms[32] = {NULL}; 8042 const PetscScalar **flips[32] = {NULL}; 8043 PetscScalar *valCopy = NULL; 8044 /* Hanging node constraints */ 8045 PetscInt *pointsC = NULL; 8046 PetscScalar *valuesC = NULL; 8047 PetscInt NclC, NiC; 8048 8049 PetscInt *idx; 8050 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8051 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8052 PetscInt idxStart, idxEnd; 8053 PetscInt nRows, nCols; 8054 8055 PetscFunctionBeginHot; 8056 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8057 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8058 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8059 PetscAssertPointer(numRows, 6); 8060 PetscAssertPointer(numCols, 7); 8061 if (indices) PetscAssertPointer(indices, 8); 8062 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8063 if (values) PetscAssertPointer(values, 10); 8064 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8065 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8066 PetscCall(PetscArrayzero(offsets, 32)); 8067 /* 1) Get points in closure */ 8068 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8069 if (useClPerm) { 8070 PetscInt depth, clsize; 8071 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8072 for (clsize = 0, p = 0; p < Ncl; p++) { 8073 PetscInt dof; 8074 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8075 clsize += dof; 8076 } 8077 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8078 } 8079 /* 2) Get number of indices on these points and field offsets from section */ 8080 for (p = 0; p < Ncl * 2; p += 2) { 8081 PetscInt dof, fdof; 8082 8083 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8084 for (f = 0; f < Nf; ++f) { 8085 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8086 offsets[f + 1] += fdof; 8087 } 8088 Ni += dof; 8089 } 8090 if (*numRows == -1) *numRows = Ni; 8091 if (*numCols == -1) *numCols = Ni; 8092 nRows = *numRows; 8093 nCols = *numCols; 8094 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8095 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8096 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8097 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8098 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8099 for (f = 0; f < PetscMax(1, Nf); ++f) { 8100 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8101 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8102 /* may need to apply sign changes to the element matrix */ 8103 if (values && flips[f]) { 8104 PetscInt foffset = offsets[f]; 8105 8106 for (p = 0; p < Ncl; ++p) { 8107 PetscInt pnt = points[2 * p], fdof; 8108 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8109 8110 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8111 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8112 if (flip) { 8113 PetscInt i, j, k; 8114 8115 if (!valCopy) { 8116 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8117 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8118 *values = valCopy; 8119 } 8120 for (i = 0; i < fdof; ++i) { 8121 PetscScalar fval = flip[i]; 8122 8123 if (multiplyRight) { 8124 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8125 } 8126 if (multiplyLeft) { 8127 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8128 } 8129 } 8130 } 8131 foffset += fdof; 8132 } 8133 } 8134 } 8135 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8136 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8137 if (NclC) { 8138 if (multiplyRight) *numCols = NiC; 8139 if (multiplyLeft) *numRows = NiC; 8140 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8141 for (f = 0; f < PetscMax(1, Nf); ++f) { 8142 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8143 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8144 } 8145 for (f = 0; f < PetscMax(1, Nf); ++f) { 8146 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8147 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8148 } 8149 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8150 Ncl = NclC; 8151 Ni = NiC; 8152 points = pointsC; 8153 if (values) *values = valuesC; 8154 } 8155 /* 5) Calculate indices */ 8156 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8157 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8158 if (Nf) { 8159 PetscInt idxOff; 8160 PetscBool useFieldOffsets; 8161 8162 if (outOffsets) { 8163 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8164 } 8165 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8166 if (useFieldOffsets) { 8167 for (p = 0; p < Ncl; ++p) { 8168 const PetscInt pnt = points[p * 2]; 8169 8170 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8171 } 8172 } else { 8173 for (p = 0; p < Ncl; ++p) { 8174 const PetscInt pnt = points[p * 2]; 8175 8176 if (pnt < idxStart || pnt >= idxEnd) continue; 8177 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8178 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8179 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8180 * global section. */ 8181 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8182 } 8183 } 8184 } else { 8185 PetscInt off = 0, idxOff; 8186 8187 for (p = 0; p < Ncl; ++p) { 8188 const PetscInt pnt = points[p * 2]; 8189 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8190 8191 if (pnt < idxStart || pnt >= idxEnd) continue; 8192 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8193 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8194 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8195 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8196 } 8197 } 8198 /* 6) Cleanup */ 8199 for (f = 0; f < PetscMax(1, Nf); ++f) { 8200 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8201 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8202 } 8203 if (NclC) { 8204 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8205 } else { 8206 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8207 } 8208 8209 if (indices) *indices = idx; 8210 PetscFunctionReturn(PETSC_SUCCESS); 8211 } 8212 8213 /*@C 8214 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8215 8216 Not collective 8217 8218 Input Parameters: 8219 + dm - The `DM` 8220 . section - The `PetscSection` describing the points (a local section) 8221 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8222 . point - The point defining the closure 8223 - useClPerm - Use the closure point permutation if available 8224 8225 Output Parameters: 8226 + numIndices - The number of dof indices in the closure of point with the input sections 8227 . indices - The dof indices 8228 . outOffsets - Array to write the field offsets into, or `NULL` 8229 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8230 8231 Level: advanced 8232 8233 Notes: 8234 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8235 8236 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8237 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8238 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8239 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8240 indices (with the above semantics) are implied. 8241 8242 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8243 `PetscSection`, `DMGetGlobalSection()` 8244 @*/ 8245 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8246 { 8247 PetscInt numRows = -1, numCols = -1; 8248 8249 PetscFunctionBeginHot; 8250 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8251 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8252 *numIndices = numRows; 8253 PetscFunctionReturn(PETSC_SUCCESS); 8254 } 8255 8256 /*@C 8257 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8258 8259 Not collective 8260 8261 Input Parameters: 8262 + dm - The `DM` 8263 . section - The `PetscSection` describing the points (a local section) 8264 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8265 . point - The point defining the closure 8266 - useClPerm - Use the closure point permutation if available 8267 8268 Output Parameters: 8269 + numIndices - The number of dof indices in the closure of point with the input sections 8270 . indices - The dof indices 8271 . outOffsets - Array to write the field offsets into, or `NULL` 8272 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8273 8274 Level: advanced 8275 8276 Notes: 8277 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8278 8279 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8280 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8281 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8282 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8283 indices (with the above semantics) are implied. 8284 8285 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8286 @*/ 8287 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8288 { 8289 PetscFunctionBegin; 8290 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8291 PetscAssertPointer(indices, 7); 8292 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8293 PetscFunctionReturn(PETSC_SUCCESS); 8294 } 8295 8296 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8297 { 8298 DM_Plex *mesh = (DM_Plex *)dm->data; 8299 PetscInt *indices; 8300 PetscInt numIndices; 8301 const PetscScalar *valuesOrig = values; 8302 PetscErrorCode ierr; 8303 8304 PetscFunctionBegin; 8305 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8306 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8307 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8308 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8309 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8310 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8311 8312 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8313 8314 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8315 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8316 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8317 if (ierr) { 8318 PetscMPIInt rank; 8319 8320 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8321 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8322 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8323 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8324 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8325 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8326 } 8327 if (mesh->printFEM > 1) { 8328 PetscInt i; 8329 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8330 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8331 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8332 } 8333 8334 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8335 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8336 PetscFunctionReturn(PETSC_SUCCESS); 8337 } 8338 8339 /*@C 8340 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8341 8342 Not collective 8343 8344 Input Parameters: 8345 + dm - The `DM` 8346 . section - The section describing the layout in `v`, or `NULL` to use the default section 8347 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8348 . A - The matrix 8349 . point - The point in the `DM` 8350 . values - The array of values 8351 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8352 8353 Level: intermediate 8354 8355 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8356 @*/ 8357 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8358 { 8359 PetscFunctionBegin; 8360 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8361 PetscFunctionReturn(PETSC_SUCCESS); 8362 } 8363 8364 /*@C 8365 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8366 8367 Not collective 8368 8369 Input Parameters: 8370 + dmRow - The `DM` for the row fields 8371 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8372 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8373 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8374 . dmCol - The `DM` for the column fields 8375 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8376 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8377 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8378 . A - The matrix 8379 . point - The point in the `DM` 8380 . values - The array of values 8381 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8382 8383 Level: intermediate 8384 8385 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8386 @*/ 8387 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) 8388 { 8389 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8390 PetscInt *indicesRow, *indicesCol; 8391 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8392 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8393 8394 PetscErrorCode ierr; 8395 8396 PetscFunctionBegin; 8397 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8398 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8399 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8400 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8401 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8402 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8403 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8404 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8405 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8406 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8407 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8408 8409 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8410 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8411 valuesV1 = valuesV0; 8412 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8413 valuesV2 = valuesV1; 8414 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8415 8416 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8417 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8418 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8419 if (ierr) { 8420 PetscMPIInt rank; 8421 8422 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8423 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8424 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8425 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8426 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8427 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8428 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8429 } 8430 8431 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8432 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8433 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8434 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8435 PetscFunctionReturn(PETSC_SUCCESS); 8436 } 8437 8438 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8439 { 8440 DM_Plex *mesh = (DM_Plex *)dmf->data; 8441 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8442 PetscInt *cpoints = NULL; 8443 PetscInt *findices, *cindices; 8444 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8445 PetscInt foffsets[32], coffsets[32]; 8446 DMPolytopeType ct; 8447 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8448 PetscErrorCode ierr; 8449 8450 PetscFunctionBegin; 8451 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8452 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8453 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8454 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8455 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8456 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8457 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8458 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8459 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8460 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8461 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8462 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8463 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8464 PetscCall(PetscArrayzero(foffsets, 32)); 8465 PetscCall(PetscArrayzero(coffsets, 32)); 8466 /* Column indices */ 8467 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8468 maxFPoints = numCPoints; 8469 /* Compress out points not in the section */ 8470 /* TODO: Squeeze out points with 0 dof as well */ 8471 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8472 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8473 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8474 cpoints[q * 2] = cpoints[p]; 8475 cpoints[q * 2 + 1] = cpoints[p + 1]; 8476 ++q; 8477 } 8478 } 8479 numCPoints = q; 8480 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8481 PetscInt fdof; 8482 8483 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8484 if (!dof) continue; 8485 for (f = 0; f < numFields; ++f) { 8486 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8487 coffsets[f + 1] += fdof; 8488 } 8489 numCIndices += dof; 8490 } 8491 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8492 /* Row indices */ 8493 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8494 { 8495 DMPlexTransform tr; 8496 DMPolytopeType *rct; 8497 PetscInt *rsize, *rcone, *rornt, Nt; 8498 8499 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8500 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8501 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8502 numSubcells = rsize[Nt - 1]; 8503 PetscCall(DMPlexTransformDestroy(&tr)); 8504 } 8505 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8506 for (r = 0, q = 0; r < numSubcells; ++r) { 8507 /* TODO Map from coarse to fine cells */ 8508 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8509 /* Compress out points not in the section */ 8510 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8511 for (p = 0; p < numFPoints * 2; p += 2) { 8512 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8513 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8514 if (!dof) continue; 8515 for (s = 0; s < q; ++s) 8516 if (fpoints[p] == ftotpoints[s * 2]) break; 8517 if (s < q) continue; 8518 ftotpoints[q * 2] = fpoints[p]; 8519 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8520 ++q; 8521 } 8522 } 8523 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8524 } 8525 numFPoints = q; 8526 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8527 PetscInt fdof; 8528 8529 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8530 if (!dof) continue; 8531 for (f = 0; f < numFields; ++f) { 8532 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8533 foffsets[f + 1] += fdof; 8534 } 8535 numFIndices += dof; 8536 } 8537 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8538 8539 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8540 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8541 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8542 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8543 if (numFields) { 8544 const PetscInt **permsF[32] = {NULL}; 8545 const PetscInt **permsC[32] = {NULL}; 8546 8547 for (f = 0; f < numFields; f++) { 8548 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8549 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8550 } 8551 for (p = 0; p < numFPoints; p++) { 8552 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8553 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8554 } 8555 for (p = 0; p < numCPoints; p++) { 8556 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8557 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8558 } 8559 for (f = 0; f < numFields; f++) { 8560 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8561 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8562 } 8563 } else { 8564 const PetscInt **permsF = NULL; 8565 const PetscInt **permsC = NULL; 8566 8567 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8568 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8569 for (p = 0, off = 0; p < numFPoints; p++) { 8570 const PetscInt *perm = permsF ? permsF[p] : NULL; 8571 8572 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8573 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8574 } 8575 for (p = 0, off = 0; p < numCPoints; p++) { 8576 const PetscInt *perm = permsC ? permsC[p] : NULL; 8577 8578 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8579 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8580 } 8581 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8582 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8583 } 8584 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8585 /* TODO: flips */ 8586 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8587 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8588 if (ierr) { 8589 PetscMPIInt rank; 8590 8591 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8592 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8593 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8594 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8595 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8596 } 8597 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8598 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8599 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8600 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8601 PetscFunctionReturn(PETSC_SUCCESS); 8602 } 8603 8604 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8605 { 8606 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8607 PetscInt *cpoints = NULL; 8608 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8609 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8610 DMPolytopeType ct; 8611 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8612 8613 PetscFunctionBegin; 8614 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8615 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8616 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8617 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8618 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8619 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8620 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8621 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8622 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8623 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8624 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8625 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8626 /* Column indices */ 8627 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8628 maxFPoints = numCPoints; 8629 /* Compress out points not in the section */ 8630 /* TODO: Squeeze out points with 0 dof as well */ 8631 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8632 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8633 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8634 cpoints[q * 2] = cpoints[p]; 8635 cpoints[q * 2 + 1] = cpoints[p + 1]; 8636 ++q; 8637 } 8638 } 8639 numCPoints = q; 8640 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8641 PetscInt fdof; 8642 8643 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8644 if (!dof) continue; 8645 for (f = 0; f < numFields; ++f) { 8646 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8647 coffsets[f + 1] += fdof; 8648 } 8649 numCIndices += dof; 8650 } 8651 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8652 /* Row indices */ 8653 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8654 { 8655 DMPlexTransform tr; 8656 DMPolytopeType *rct; 8657 PetscInt *rsize, *rcone, *rornt, Nt; 8658 8659 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8660 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8661 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8662 numSubcells = rsize[Nt - 1]; 8663 PetscCall(DMPlexTransformDestroy(&tr)); 8664 } 8665 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8666 for (r = 0, q = 0; r < numSubcells; ++r) { 8667 /* TODO Map from coarse to fine cells */ 8668 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8669 /* Compress out points not in the section */ 8670 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8671 for (p = 0; p < numFPoints * 2; p += 2) { 8672 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8673 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8674 if (!dof) continue; 8675 for (s = 0; s < q; ++s) 8676 if (fpoints[p] == ftotpoints[s * 2]) break; 8677 if (s < q) continue; 8678 ftotpoints[q * 2] = fpoints[p]; 8679 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8680 ++q; 8681 } 8682 } 8683 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8684 } 8685 numFPoints = q; 8686 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8687 PetscInt fdof; 8688 8689 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8690 if (!dof) continue; 8691 for (f = 0; f < numFields; ++f) { 8692 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8693 foffsets[f + 1] += fdof; 8694 } 8695 numFIndices += dof; 8696 } 8697 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8698 8699 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8700 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8701 if (numFields) { 8702 const PetscInt **permsF[32] = {NULL}; 8703 const PetscInt **permsC[32] = {NULL}; 8704 8705 for (f = 0; f < numFields; f++) { 8706 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8707 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8708 } 8709 for (p = 0; p < numFPoints; p++) { 8710 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8711 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8712 } 8713 for (p = 0; p < numCPoints; p++) { 8714 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8715 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8716 } 8717 for (f = 0; f < numFields; f++) { 8718 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8719 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8720 } 8721 } else { 8722 const PetscInt **permsF = NULL; 8723 const PetscInt **permsC = NULL; 8724 8725 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8726 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8727 for (p = 0, off = 0; p < numFPoints; p++) { 8728 const PetscInt *perm = permsF ? permsF[p] : NULL; 8729 8730 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8731 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8732 } 8733 for (p = 0, off = 0; p < numCPoints; p++) { 8734 const PetscInt *perm = permsC ? permsC[p] : NULL; 8735 8736 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8737 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8738 } 8739 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8740 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8741 } 8742 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8743 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8744 PetscFunctionReturn(PETSC_SUCCESS); 8745 } 8746 8747 /*@ 8748 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8749 8750 Input Parameter: 8751 . dm - The `DMPLEX` object 8752 8753 Output Parameter: 8754 . cellHeight - The height of a cell 8755 8756 Level: developer 8757 8758 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8759 @*/ 8760 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8761 { 8762 DM_Plex *mesh = (DM_Plex *)dm->data; 8763 8764 PetscFunctionBegin; 8765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8766 PetscAssertPointer(cellHeight, 2); 8767 *cellHeight = mesh->vtkCellHeight; 8768 PetscFunctionReturn(PETSC_SUCCESS); 8769 } 8770 8771 /*@ 8772 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8773 8774 Input Parameters: 8775 + dm - The `DMPLEX` object 8776 - cellHeight - The height of a cell 8777 8778 Level: developer 8779 8780 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8781 @*/ 8782 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8783 { 8784 DM_Plex *mesh = (DM_Plex *)dm->data; 8785 8786 PetscFunctionBegin; 8787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8788 mesh->vtkCellHeight = cellHeight; 8789 PetscFunctionReturn(PETSC_SUCCESS); 8790 } 8791 8792 /*@ 8793 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8794 8795 Input Parameters: 8796 + dm - The `DMPLEX` object 8797 - ct - The `DMPolytopeType` of the cell 8798 8799 Output Parameters: 8800 + start - The first cell of this type, or `NULL` 8801 - end - The upper bound on this celltype, or `NULL` 8802 8803 Level: advanced 8804 8805 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8806 @*/ 8807 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end) 8808 { 8809 DM_Plex *mesh = (DM_Plex *)dm->data; 8810 DMLabel label; 8811 PetscInt pStart, pEnd; 8812 8813 PetscFunctionBegin; 8814 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8815 if (start) { 8816 PetscAssertPointer(start, 3); 8817 *start = 0; 8818 } 8819 if (end) { 8820 PetscAssertPointer(end, 4); 8821 *end = 0; 8822 } 8823 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8824 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8825 if (mesh->tr) { 8826 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8827 } else { 8828 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8829 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8830 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8831 } 8832 PetscFunctionReturn(PETSC_SUCCESS); 8833 } 8834 8835 /*@ 8836 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8837 8838 Input Parameters: 8839 + dm - The `DMPLEX` object 8840 - depth - The depth for the given point stratum 8841 8842 Output Parameter: 8843 . gsize - The global number of points in the stratum 8844 8845 Level: advanced 8846 8847 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8848 @*/ 8849 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8850 { 8851 PetscSF sf; 8852 const PetscInt *leaves; 8853 PetscInt Nl, loc, start, end, lsize = 0; 8854 8855 PetscFunctionBegin; 8856 PetscCall(DMGetPointSF(dm, &sf)); 8857 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8858 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8859 for (PetscInt p = start; p < end; ++p) { 8860 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8861 if (loc < 0) ++lsize; 8862 } 8863 PetscCallMPI(MPI_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8864 PetscFunctionReturn(PETSC_SUCCESS); 8865 } 8866 8867 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8868 { 8869 PetscSection section, globalSection; 8870 PetscInt *numbers, p; 8871 8872 PetscFunctionBegin; 8873 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8874 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8875 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8876 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8877 PetscCall(PetscSectionSetUp(section)); 8878 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8879 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8880 for (p = pStart; p < pEnd; ++p) { 8881 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8882 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8883 else numbers[p - pStart] += shift; 8884 } 8885 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8886 if (globalSize) { 8887 PetscLayout layout; 8888 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8889 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8890 PetscCall(PetscLayoutDestroy(&layout)); 8891 } 8892 PetscCall(PetscSectionDestroy(§ion)); 8893 PetscCall(PetscSectionDestroy(&globalSection)); 8894 PetscFunctionReturn(PETSC_SUCCESS); 8895 } 8896 8897 /*@ 8898 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8899 8900 Input Parameters: 8901 + dm - The `DMPLEX` object 8902 - includeAll - Whether to include all cells, or just the simplex and box cells 8903 8904 Output Parameter: 8905 . globalCellNumbers - Global cell numbers for all cells on this process 8906 8907 Level: developer 8908 8909 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8910 @*/ 8911 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8912 { 8913 PetscInt cellHeight, cStart, cEnd; 8914 8915 PetscFunctionBegin; 8916 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8917 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8918 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8919 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8920 PetscFunctionReturn(PETSC_SUCCESS); 8921 } 8922 8923 /*@ 8924 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8925 8926 Input Parameter: 8927 . dm - The `DMPLEX` object 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`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8935 @*/ 8936 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8937 { 8938 DM_Plex *mesh = (DM_Plex *)dm->data; 8939 8940 PetscFunctionBegin; 8941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8942 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8943 *globalCellNumbers = mesh->globalCellNumbers; 8944 PetscFunctionReturn(PETSC_SUCCESS); 8945 } 8946 8947 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8948 { 8949 PetscInt vStart, vEnd; 8950 8951 PetscFunctionBegin; 8952 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8953 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8954 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8955 PetscFunctionReturn(PETSC_SUCCESS); 8956 } 8957 8958 /*@ 8959 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8960 8961 Input Parameter: 8962 . dm - The `DMPLEX` object 8963 8964 Output Parameter: 8965 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8966 8967 Level: developer 8968 8969 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8970 @*/ 8971 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8972 { 8973 DM_Plex *mesh = (DM_Plex *)dm->data; 8974 8975 PetscFunctionBegin; 8976 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8977 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8978 *globalVertexNumbers = mesh->globalVertexNumbers; 8979 PetscFunctionReturn(PETSC_SUCCESS); 8980 } 8981 8982 /*@ 8983 DMPlexCreatePointNumbering - Create a global numbering for all points. 8984 8985 Collective 8986 8987 Input Parameter: 8988 . dm - The `DMPLEX` object 8989 8990 Output Parameter: 8991 . globalPointNumbers - Global numbers for all points on this process 8992 8993 Level: developer 8994 8995 Notes: 8996 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8997 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8998 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8999 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 9000 9001 The partitioned mesh is 9002 ``` 9003 (2)--0--(3)--1--(4) (1)--0--(2) 9004 ``` 9005 and its global numbering is 9006 ``` 9007 (3)--0--(4)--1--(5)--2--(6) 9008 ``` 9009 Then the global numbering is provided as 9010 ``` 9011 [0] Number of indices in set 5 9012 [0] 0 0 9013 [0] 1 1 9014 [0] 2 3 9015 [0] 3 4 9016 [0] 4 -6 9017 [1] Number of indices in set 3 9018 [1] 0 2 9019 [1] 1 5 9020 [1] 2 6 9021 ``` 9022 9023 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9024 @*/ 9025 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 9026 { 9027 IS nums[4]; 9028 PetscInt depths[4], gdepths[4], starts[4]; 9029 PetscInt depth, d, shift = 0; 9030 PetscBool empty = PETSC_FALSE; 9031 9032 PetscFunctionBegin; 9033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9034 PetscCall(DMPlexGetDepth(dm, &depth)); 9035 // For unstratified meshes use dim instead of depth 9036 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9037 // If any stratum is empty, we must mark all empty 9038 for (d = 0; d <= depth; ++d) { 9039 PetscInt end; 9040 9041 depths[d] = depth - d; 9042 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9043 if (!(starts[d] - end)) empty = PETSC_TRUE; 9044 } 9045 if (empty) 9046 for (d = 0; d <= depth; ++d) { 9047 depths[d] = -1; 9048 starts[d] = -1; 9049 } 9050 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9051 PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9052 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]); 9053 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9054 for (d = 0; d <= depth; ++d) { 9055 PetscInt pStart, pEnd, gsize; 9056 9057 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9058 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9059 shift += gsize; 9060 } 9061 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9062 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9063 PetscFunctionReturn(PETSC_SUCCESS); 9064 } 9065 9066 /*@ 9067 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9068 9069 Collective 9070 9071 Input Parameter: 9072 . dm - The `DMPLEX` object 9073 9074 Output Parameter: 9075 . globalEdgeNumbers - Global numbers for all edges on this process 9076 9077 Level: developer 9078 9079 Notes: 9080 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). 9081 9082 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9083 @*/ 9084 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9085 { 9086 PetscSF sf; 9087 PetscInt eStart, eEnd; 9088 9089 PetscFunctionBegin; 9090 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9091 PetscCall(DMGetPointSF(dm, &sf)); 9092 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9093 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9094 PetscFunctionReturn(PETSC_SUCCESS); 9095 } 9096 9097 /*@ 9098 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9099 9100 Input Parameter: 9101 . dm - The `DMPLEX` object 9102 9103 Output Parameter: 9104 . ranks - The rank field 9105 9106 Options Database Key: 9107 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9108 9109 Level: intermediate 9110 9111 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9112 @*/ 9113 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9114 { 9115 DM rdm; 9116 PetscFE fe; 9117 PetscScalar *r; 9118 PetscMPIInt rank; 9119 DMPolytopeType ct; 9120 PetscInt dim, cStart, cEnd, c; 9121 PetscBool simplex; 9122 9123 PetscFunctionBeginUser; 9124 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9125 PetscAssertPointer(ranks, 2); 9126 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9127 PetscCall(DMClone(dm, &rdm)); 9128 PetscCall(DMGetDimension(rdm, &dim)); 9129 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9130 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9131 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9132 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9133 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9134 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9135 PetscCall(PetscFEDestroy(&fe)); 9136 PetscCall(DMCreateDS(rdm)); 9137 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9138 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9139 PetscCall(VecGetArray(*ranks, &r)); 9140 for (c = cStart; c < cEnd; ++c) { 9141 PetscScalar *lr; 9142 9143 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9144 if (lr) *lr = rank; 9145 } 9146 PetscCall(VecRestoreArray(*ranks, &r)); 9147 PetscCall(DMDestroy(&rdm)); 9148 PetscFunctionReturn(PETSC_SUCCESS); 9149 } 9150 9151 /*@ 9152 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9153 9154 Input Parameters: 9155 + dm - The `DMPLEX` 9156 - label - The `DMLabel` 9157 9158 Output Parameter: 9159 . val - The label value field 9160 9161 Options Database Key: 9162 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9163 9164 Level: intermediate 9165 9166 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9167 @*/ 9168 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9169 { 9170 DM rdm, plex; 9171 Vec lval; 9172 PetscSection section; 9173 PetscFE fe; 9174 PetscScalar *v; 9175 PetscInt dim, pStart, pEnd, p, cStart; 9176 DMPolytopeType ct; 9177 char name[PETSC_MAX_PATH_LEN]; 9178 const char *lname, *prefix; 9179 9180 PetscFunctionBeginUser; 9181 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9182 PetscAssertPointer(label, 2); 9183 PetscAssertPointer(val, 3); 9184 PetscCall(DMClone(dm, &rdm)); 9185 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9186 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9187 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9188 PetscCall(DMDestroy(&plex)); 9189 PetscCall(DMGetDimension(rdm, &dim)); 9190 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9191 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9192 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9193 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9194 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9195 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9196 PetscCall(PetscFEDestroy(&fe)); 9197 PetscCall(DMCreateDS(rdm)); 9198 PetscCall(DMCreateGlobalVector(rdm, val)); 9199 PetscCall(DMCreateLocalVector(rdm, &lval)); 9200 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9201 PetscCall(DMGetLocalSection(rdm, §ion)); 9202 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9203 PetscCall(VecGetArray(lval, &v)); 9204 for (p = pStart; p < pEnd; ++p) { 9205 PetscInt cval, dof, off; 9206 9207 PetscCall(PetscSectionGetDof(section, p, &dof)); 9208 if (!dof) continue; 9209 PetscCall(DMLabelGetValue(label, p, &cval)); 9210 PetscCall(PetscSectionGetOffset(section, p, &off)); 9211 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9212 } 9213 PetscCall(VecRestoreArray(lval, &v)); 9214 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9215 PetscCall(VecDestroy(&lval)); 9216 PetscCall(DMDestroy(&rdm)); 9217 PetscFunctionReturn(PETSC_SUCCESS); 9218 } 9219 9220 /*@ 9221 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9222 9223 Input Parameter: 9224 . dm - The `DMPLEX` object 9225 9226 Level: developer 9227 9228 Notes: 9229 This is a useful diagnostic when creating meshes programmatically. 9230 9231 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9232 9233 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9234 @*/ 9235 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9236 { 9237 PetscSection coneSection, supportSection; 9238 const PetscInt *cone, *support; 9239 PetscInt coneSize, c, supportSize, s; 9240 PetscInt pStart, pEnd, p, pp, csize, ssize; 9241 PetscBool storagecheck = PETSC_TRUE; 9242 9243 PetscFunctionBegin; 9244 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9245 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9246 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9247 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9248 /* Check that point p is found in the support of its cone points, and vice versa */ 9249 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9250 for (p = pStart; p < pEnd; ++p) { 9251 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9252 PetscCall(DMPlexGetCone(dm, p, &cone)); 9253 for (c = 0; c < coneSize; ++c) { 9254 PetscBool dup = PETSC_FALSE; 9255 PetscInt d; 9256 for (d = c - 1; d >= 0; --d) { 9257 if (cone[c] == cone[d]) { 9258 dup = PETSC_TRUE; 9259 break; 9260 } 9261 } 9262 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9263 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9264 for (s = 0; s < supportSize; ++s) { 9265 if (support[s] == p) break; 9266 } 9267 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9268 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9269 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9270 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9271 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9272 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9273 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9274 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]); 9275 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9276 } 9277 } 9278 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9279 if (p != pp) { 9280 storagecheck = PETSC_FALSE; 9281 continue; 9282 } 9283 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9284 PetscCall(DMPlexGetSupport(dm, p, &support)); 9285 for (s = 0; s < supportSize; ++s) { 9286 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9287 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9288 for (c = 0; c < coneSize; ++c) { 9289 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9290 if (cone[c] != pp) { 9291 c = 0; 9292 break; 9293 } 9294 if (cone[c] == p) break; 9295 } 9296 if (c >= coneSize) { 9297 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9298 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9299 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9300 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9301 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9302 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9303 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9304 } 9305 } 9306 } 9307 if (storagecheck) { 9308 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9309 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9310 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9311 } 9312 PetscFunctionReturn(PETSC_SUCCESS); 9313 } 9314 9315 /* 9316 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. 9317 */ 9318 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9319 { 9320 DMPolytopeType cct; 9321 PetscInt ptpoints[4]; 9322 const PetscInt *cone, *ccone, *ptcone; 9323 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9324 9325 PetscFunctionBegin; 9326 *unsplit = 0; 9327 switch (ct) { 9328 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9329 ptpoints[npt++] = c; 9330 break; 9331 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9332 PetscCall(DMPlexGetCone(dm, c, &cone)); 9333 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9334 for (cp = 0; cp < coneSize; ++cp) { 9335 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9336 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9337 } 9338 break; 9339 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9340 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9341 PetscCall(DMPlexGetCone(dm, c, &cone)); 9342 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9343 for (cp = 0; cp < coneSize; ++cp) { 9344 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9345 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9346 for (ccp = 0; ccp < cconeSize; ++ccp) { 9347 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9348 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9349 PetscInt p; 9350 for (p = 0; p < npt; ++p) 9351 if (ptpoints[p] == ccone[ccp]) break; 9352 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9353 } 9354 } 9355 } 9356 break; 9357 default: 9358 break; 9359 } 9360 for (pt = 0; pt < npt; ++pt) { 9361 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9362 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9363 } 9364 PetscFunctionReturn(PETSC_SUCCESS); 9365 } 9366 9367 /*@ 9368 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9369 9370 Input Parameters: 9371 + dm - The `DMPLEX` object 9372 - cellHeight - Normally 0 9373 9374 Level: developer 9375 9376 Notes: 9377 This is a useful diagnostic when creating meshes programmatically. 9378 Currently applicable only to homogeneous simplex or tensor meshes. 9379 9380 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9381 9382 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9383 @*/ 9384 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9385 { 9386 DMPlexInterpolatedFlag interp; 9387 DMPolytopeType ct; 9388 PetscInt vStart, vEnd, cStart, cEnd, c; 9389 9390 PetscFunctionBegin; 9391 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9392 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9393 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9394 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9395 for (c = cStart; c < cEnd; ++c) { 9396 PetscInt *closure = NULL; 9397 PetscInt coneSize, closureSize, cl, Nv = 0; 9398 9399 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9400 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9401 if (interp == DMPLEX_INTERPOLATED_FULL) { 9402 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9403 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)); 9404 } 9405 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9406 for (cl = 0; cl < closureSize * 2; cl += 2) { 9407 const PetscInt p = closure[cl]; 9408 if ((p >= vStart) && (p < vEnd)) ++Nv; 9409 } 9410 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9411 /* Special Case: Tensor faces with identified vertices */ 9412 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9413 PetscInt unsplit; 9414 9415 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9416 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9417 } 9418 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)); 9419 } 9420 PetscFunctionReturn(PETSC_SUCCESS); 9421 } 9422 9423 /*@ 9424 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9425 9426 Collective 9427 9428 Input Parameters: 9429 + dm - The `DMPLEX` object 9430 - cellHeight - Normally 0 9431 9432 Level: developer 9433 9434 Notes: 9435 This is a useful diagnostic when creating meshes programmatically. 9436 This routine is only relevant for meshes that are fully interpolated across all ranks. 9437 It will error out if a partially interpolated mesh is given on some rank. 9438 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9439 9440 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9441 9442 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9443 @*/ 9444 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9445 { 9446 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9447 DMPlexInterpolatedFlag interpEnum; 9448 9449 PetscFunctionBegin; 9450 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9451 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9452 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9453 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9454 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9455 PetscFunctionReturn(PETSC_SUCCESS); 9456 } 9457 9458 PetscCall(DMGetDimension(dm, &dim)); 9459 PetscCall(DMPlexGetDepth(dm, &depth)); 9460 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9461 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9462 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9463 for (c = cStart; c < cEnd; ++c) { 9464 const PetscInt *cone, *ornt, *faceSizes, *faces; 9465 const DMPolytopeType *faceTypes; 9466 DMPolytopeType ct; 9467 PetscInt numFaces, coneSize, f; 9468 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9469 9470 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9471 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9472 if (unsplit) continue; 9473 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9474 PetscCall(DMPlexGetCone(dm, c, &cone)); 9475 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9476 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9477 for (cl = 0; cl < closureSize * 2; cl += 2) { 9478 const PetscInt p = closure[cl]; 9479 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9480 } 9481 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9482 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); 9483 for (f = 0; f < numFaces; ++f) { 9484 DMPolytopeType fct; 9485 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9486 9487 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9488 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9489 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9490 const PetscInt p = fclosure[cl]; 9491 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9492 } 9493 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]); 9494 for (v = 0; v < fnumCorners; ++v) { 9495 if (fclosure[v] != faces[fOff + v]) { 9496 PetscInt v1; 9497 9498 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9499 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9500 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9501 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9502 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9503 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]); 9504 } 9505 } 9506 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9507 fOff += faceSizes[f]; 9508 } 9509 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9510 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9511 } 9512 } 9513 PetscFunctionReturn(PETSC_SUCCESS); 9514 } 9515 9516 /*@ 9517 DMPlexCheckGeometry - Check the geometry of mesh cells 9518 9519 Input Parameter: 9520 . dm - The `DMPLEX` object 9521 9522 Level: developer 9523 9524 Notes: 9525 This is a useful diagnostic when creating meshes programmatically. 9526 9527 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9528 9529 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9530 @*/ 9531 PetscErrorCode DMPlexCheckGeometry(DM dm) 9532 { 9533 Vec coordinates; 9534 PetscReal detJ, J[9], refVol = 1.0; 9535 PetscReal vol; 9536 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9537 9538 PetscFunctionBegin; 9539 PetscCall(DMGetDimension(dm, &dim)); 9540 PetscCall(DMGetCoordinateDim(dm, &dE)); 9541 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9542 PetscCall(DMPlexGetDepth(dm, &depth)); 9543 for (d = 0; d < dim; ++d) refVol *= 2.0; 9544 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9545 /* Make sure local coordinates are created, because that step is collective */ 9546 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9547 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9548 for (c = cStart; c < cEnd; ++c) { 9549 DMPolytopeType ct; 9550 PetscInt unsplit; 9551 PetscBool ignoreZeroVol = PETSC_FALSE; 9552 9553 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9554 switch (ct) { 9555 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9556 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9557 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9558 ignoreZeroVol = PETSC_TRUE; 9559 break; 9560 default: 9561 break; 9562 } 9563 switch (ct) { 9564 case DM_POLYTOPE_TRI_PRISM: 9565 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9566 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9567 case DM_POLYTOPE_PYRAMID: 9568 continue; 9569 default: 9570 break; 9571 } 9572 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9573 if (unsplit) continue; 9574 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9575 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); 9576 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9577 /* This should work with periodicity since DG coordinates should be used */ 9578 if (depth > 1) { 9579 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9580 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); 9581 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9582 } 9583 } 9584 PetscFunctionReturn(PETSC_SUCCESS); 9585 } 9586 9587 /*@ 9588 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9589 9590 Collective 9591 9592 Input Parameters: 9593 + dm - The `DMPLEX` object 9594 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9595 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9596 9597 Level: developer 9598 9599 Notes: 9600 This is mainly intended for debugging/testing purposes. 9601 9602 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9603 9604 Extra roots can come from periodic cuts, where additional points appear on the boundary 9605 9606 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9607 @*/ 9608 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9609 { 9610 PetscInt l, nleaves, nroots, overlap; 9611 const PetscInt *locals; 9612 const PetscSFNode *remotes; 9613 PetscBool distributed; 9614 MPI_Comm comm; 9615 PetscMPIInt rank; 9616 9617 PetscFunctionBegin; 9618 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9619 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9620 else pointSF = dm->sf; 9621 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9622 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9623 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9624 { 9625 PetscMPIInt mpiFlag; 9626 9627 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9628 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9629 } 9630 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9631 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9632 if (!distributed) { 9633 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); 9634 PetscFunctionReturn(PETSC_SUCCESS); 9635 } 9636 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); 9637 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9638 9639 /* Check SF graph is compatible with DMPlex chart */ 9640 { 9641 PetscInt pStart, pEnd, maxLeaf; 9642 9643 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9644 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9645 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9646 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9647 } 9648 9649 /* Check Point SF has no local points referenced */ 9650 for (l = 0; l < nleaves; l++) { 9651 PetscMPIInt irank; 9652 9653 PetscCall(PetscMPIIntCast(remotes[l].rank, &irank)); 9654 PetscAssert(irank != rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%d,%" PetscInt_FMT ")", locals ? locals[l] : l, irank, remotes[l].index); 9655 } 9656 9657 /* Check there are no cells in interface */ 9658 if (!overlap) { 9659 PetscInt cellHeight, cStart, cEnd; 9660 9661 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9662 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9663 for (l = 0; l < nleaves; ++l) { 9664 const PetscInt point = locals ? locals[l] : l; 9665 9666 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9667 } 9668 } 9669 9670 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9671 { 9672 const PetscInt *rootdegree; 9673 9674 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9675 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9676 for (l = 0; l < nleaves; ++l) { 9677 const PetscInt point = locals ? locals[l] : l; 9678 const PetscInt *cone; 9679 PetscInt coneSize, c, idx; 9680 9681 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9682 PetscCall(DMPlexGetCone(dm, point, &cone)); 9683 for (c = 0; c < coneSize; ++c) { 9684 if (!rootdegree[cone[c]]) { 9685 if (locals) { 9686 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9687 } else { 9688 idx = (cone[c] < nleaves) ? cone[c] : -1; 9689 } 9690 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9691 } 9692 } 9693 } 9694 } 9695 PetscFunctionReturn(PETSC_SUCCESS); 9696 } 9697 9698 /*@ 9699 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9700 9701 Collective 9702 9703 Input Parameter: 9704 . dm - The `DMPLEX` object 9705 9706 Level: developer 9707 9708 Notes: 9709 This is mainly intended for debugging/testing purposes. 9710 9711 Other cell types which are disconnected would be caught by the symmetry and face checks. 9712 9713 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9714 9715 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9716 @*/ 9717 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9718 { 9719 PetscInt pStart, pEnd, vStart, vEnd; 9720 9721 PetscFunctionBegin; 9722 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9723 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9724 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9725 for (PetscInt v = vStart; v < vEnd; ++v) { 9726 PetscInt suppSize; 9727 9728 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9729 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9730 } 9731 PetscFunctionReturn(PETSC_SUCCESS); 9732 } 9733 9734 /*@ 9735 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9736 9737 Input Parameter: 9738 . dm - The `DMPLEX` object 9739 9740 Level: developer 9741 9742 Notes: 9743 This is a useful diagnostic when creating meshes programmatically. 9744 9745 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9746 9747 Currently does not include `DMPlexCheckCellShape()`. 9748 9749 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9750 @*/ 9751 PetscErrorCode DMPlexCheck(DM dm) 9752 { 9753 PetscInt cellHeight; 9754 9755 PetscFunctionBegin; 9756 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9757 PetscCall(DMPlexCheckSymmetry(dm)); 9758 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9759 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9760 PetscCall(DMPlexCheckGeometry(dm)); 9761 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9762 PetscCall(DMPlexCheckInterfaceCones(dm)); 9763 PetscCall(DMPlexCheckOrphanVertices(dm)); 9764 PetscFunctionReturn(PETSC_SUCCESS); 9765 } 9766 9767 typedef struct cell_stats { 9768 PetscReal min, max, sum, squaresum; 9769 PetscInt count; 9770 } cell_stats_t; 9771 9772 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9773 { 9774 PetscInt i, N = *len; 9775 9776 for (i = 0; i < N; i++) { 9777 cell_stats_t *A = (cell_stats_t *)a; 9778 cell_stats_t *B = (cell_stats_t *)b; 9779 9780 B->min = PetscMin(A->min, B->min); 9781 B->max = PetscMax(A->max, B->max); 9782 B->sum += A->sum; 9783 B->squaresum += A->squaresum; 9784 B->count += A->count; 9785 } 9786 } 9787 9788 /*@ 9789 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9790 9791 Collective 9792 9793 Input Parameters: 9794 + dm - The `DMPLEX` object 9795 . output - If true, statistics will be displayed on `stdout` 9796 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9797 9798 Level: developer 9799 9800 Notes: 9801 This is mainly intended for debugging/testing purposes. 9802 9803 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9804 9805 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9806 @*/ 9807 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9808 { 9809 DM dmCoarse; 9810 cell_stats_t stats, globalStats; 9811 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9812 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9813 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9814 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9815 PetscMPIInt rank, size; 9816 9817 PetscFunctionBegin; 9818 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9819 stats.min = PETSC_MAX_REAL; 9820 stats.max = PETSC_MIN_REAL; 9821 stats.sum = stats.squaresum = 0.; 9822 stats.count = 0; 9823 9824 PetscCallMPI(MPI_Comm_size(comm, &size)); 9825 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9826 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9827 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9828 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9829 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9830 for (c = cStart; c < cEnd; c++) { 9831 PetscInt i; 9832 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9833 9834 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9835 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9836 for (i = 0; i < PetscSqr(cdim); ++i) { 9837 frobJ += J[i] * J[i]; 9838 frobInvJ += invJ[i] * invJ[i]; 9839 } 9840 cond2 = frobJ * frobInvJ; 9841 cond = PetscSqrtReal(cond2); 9842 9843 stats.min = PetscMin(stats.min, cond); 9844 stats.max = PetscMax(stats.max, cond); 9845 stats.sum += cond; 9846 stats.squaresum += cond2; 9847 stats.count++; 9848 if (output && cond > limit) { 9849 PetscSection coordSection; 9850 Vec coordsLocal; 9851 PetscScalar *coords = NULL; 9852 PetscInt Nv, d, clSize, cl, *closure = NULL; 9853 9854 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9855 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9856 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9857 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9858 for (i = 0; i < Nv / cdim; ++i) { 9859 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9860 for (d = 0; d < cdim; ++d) { 9861 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9862 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9863 } 9864 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9865 } 9866 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9867 for (cl = 0; cl < clSize * 2; cl += 2) { 9868 const PetscInt edge = closure[cl]; 9869 9870 if ((edge >= eStart) && (edge < eEnd)) { 9871 PetscReal len; 9872 9873 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9874 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9875 } 9876 } 9877 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9878 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9879 } 9880 } 9881 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9882 9883 if (size > 1) { 9884 PetscMPIInt blockLengths[2] = {4, 1}; 9885 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9886 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9887 MPI_Op statReduce; 9888 9889 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9890 PetscCallMPI(MPI_Type_commit(&statType)); 9891 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9892 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9893 PetscCallMPI(MPI_Op_free(&statReduce)); 9894 PetscCallMPI(MPI_Type_free(&statType)); 9895 } else { 9896 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9897 } 9898 if (rank == 0) { 9899 count = globalStats.count; 9900 min = globalStats.min; 9901 max = globalStats.max; 9902 mean = globalStats.sum / globalStats.count; 9903 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9904 } 9905 9906 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)); 9907 PetscCall(PetscFree2(J, invJ)); 9908 9909 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9910 if (dmCoarse) { 9911 PetscBool isplex; 9912 9913 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9914 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9915 } 9916 PetscFunctionReturn(PETSC_SUCCESS); 9917 } 9918 9919 /*@ 9920 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9921 orthogonal quality below given tolerance. 9922 9923 Collective 9924 9925 Input Parameters: 9926 + dm - The `DMPLEX` object 9927 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9928 - atol - [0, 1] Absolute tolerance for tagging cells. 9929 9930 Output Parameters: 9931 + OrthQual - `Vec` containing orthogonal quality per cell 9932 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9933 9934 Options Database Keys: 9935 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9936 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9937 9938 Level: intermediate 9939 9940 Notes: 9941 Orthogonal quality is given by the following formula\: 9942 9943 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9944 9945 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 9946 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9947 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9948 calculating the cosine of the angle between these vectors. 9949 9950 Orthogonal quality ranges from 1 (best) to 0 (worst). 9951 9952 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9953 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9954 9955 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9956 9957 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9958 @*/ 9959 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9960 { 9961 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9962 PetscInt *idx; 9963 PetscScalar *oqVals; 9964 const PetscScalar *cellGeomArr, *faceGeomArr; 9965 PetscReal *ci, *fi, *Ai; 9966 MPI_Comm comm; 9967 Vec cellgeom, facegeom; 9968 DM dmFace, dmCell; 9969 IS glob; 9970 ISLocalToGlobalMapping ltog; 9971 PetscViewer vwr; 9972 9973 PetscFunctionBegin; 9974 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9975 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9976 PetscAssertPointer(OrthQual, 4); 9977 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9978 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9979 PetscCall(DMGetDimension(dm, &nc)); 9980 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9981 { 9982 DMPlexInterpolatedFlag interpFlag; 9983 9984 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9985 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9986 PetscMPIInt rank; 9987 9988 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9989 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9990 } 9991 } 9992 if (OrthQualLabel) { 9993 PetscAssertPointer(OrthQualLabel, 5); 9994 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9995 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9996 } else { 9997 *OrthQualLabel = NULL; 9998 } 9999 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 10000 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 10001 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 10002 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 10003 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 10004 PetscCall(VecCreate(comm, OrthQual)); 10005 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 10006 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 10007 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 10008 PetscCall(VecSetUp(*OrthQual)); 10009 PetscCall(ISDestroy(&glob)); 10010 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 10011 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 10012 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 10013 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 10014 PetscCall(VecGetDM(cellgeom, &dmCell)); 10015 PetscCall(VecGetDM(facegeom, &dmFace)); 10016 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 10017 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 10018 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 10019 PetscInt cellarr[2], *adj = NULL; 10020 PetscScalar *cArr, *fArr; 10021 PetscReal minvalc = 1.0, minvalf = 1.0; 10022 PetscFVCellGeom *cg; 10023 10024 idx[cellIter] = cell - cStart; 10025 cellarr[0] = cell; 10026 /* Make indexing into cellGeom easier */ 10027 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10028 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10029 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10030 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10031 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10032 PetscInt i; 10033 const PetscInt neigh = adj[cellneigh]; 10034 PetscReal normci = 0, normfi = 0, normai = 0; 10035 PetscFVCellGeom *cgneigh; 10036 PetscFVFaceGeom *fg; 10037 10038 /* Don't count ourselves in the neighbor list */ 10039 if (neigh == cell) continue; 10040 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10041 cellarr[1] = neigh; 10042 { 10043 PetscInt numcovpts; 10044 const PetscInt *covpts; 10045 10046 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10047 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10048 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10049 } 10050 10051 /* Compute c_i, f_i and their norms */ 10052 for (i = 0; i < nc; i++) { 10053 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10054 fi[i] = fg->centroid[i] - cg->centroid[i]; 10055 Ai[i] = fg->normal[i]; 10056 normci += PetscPowReal(ci[i], 2); 10057 normfi += PetscPowReal(fi[i], 2); 10058 normai += PetscPowReal(Ai[i], 2); 10059 } 10060 normci = PetscSqrtReal(normci); 10061 normfi = PetscSqrtReal(normfi); 10062 normai = PetscSqrtReal(normai); 10063 10064 /* Normalize and compute for each face-cell-normal pair */ 10065 for (i = 0; i < nc; i++) { 10066 ci[i] = ci[i] / normci; 10067 fi[i] = fi[i] / normfi; 10068 Ai[i] = Ai[i] / normai; 10069 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10070 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10071 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10072 } 10073 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10074 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10075 } 10076 PetscCall(PetscFree(adj)); 10077 PetscCall(PetscFree2(cArr, fArr)); 10078 /* Defer to cell if they're equal */ 10079 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10080 if (OrthQualLabel) { 10081 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10082 } 10083 } 10084 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10085 PetscCall(VecAssemblyBegin(*OrthQual)); 10086 PetscCall(VecAssemblyEnd(*OrthQual)); 10087 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10088 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10089 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10090 if (OrthQualLabel) { 10091 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10092 } 10093 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10094 PetscCall(PetscViewerDestroy(&vwr)); 10095 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10096 PetscFunctionReturn(PETSC_SUCCESS); 10097 } 10098 10099 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10100 * interpolator construction */ 10101 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10102 { 10103 PetscSection section, newSection, gsection; 10104 PetscSF sf; 10105 PetscBool hasConstraints, ghasConstraints; 10106 10107 PetscFunctionBegin; 10108 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10109 PetscAssertPointer(odm, 2); 10110 PetscCall(DMGetLocalSection(dm, §ion)); 10111 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10112 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10113 if (!ghasConstraints) { 10114 PetscCall(PetscObjectReference((PetscObject)dm)); 10115 *odm = dm; 10116 PetscFunctionReturn(PETSC_SUCCESS); 10117 } 10118 PetscCall(DMClone(dm, odm)); 10119 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10120 PetscCall(DMGetLocalSection(*odm, &newSection)); 10121 PetscCall(DMGetPointSF(*odm, &sf)); 10122 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10123 PetscCall(DMSetGlobalSection(*odm, gsection)); 10124 PetscCall(PetscSectionDestroy(&gsection)); 10125 PetscFunctionReturn(PETSC_SUCCESS); 10126 } 10127 10128 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10129 { 10130 DM dmco, dmfo; 10131 Mat interpo; 10132 Vec rscale; 10133 Vec cglobalo, clocal; 10134 Vec fglobal, fglobalo, flocal; 10135 PetscBool regular; 10136 10137 PetscFunctionBegin; 10138 PetscCall(DMGetFullDM(dmc, &dmco)); 10139 PetscCall(DMGetFullDM(dmf, &dmfo)); 10140 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10141 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10142 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10143 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10144 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10145 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10146 PetscCall(VecSet(cglobalo, 0.)); 10147 PetscCall(VecSet(clocal, 0.)); 10148 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10149 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10150 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10151 PetscCall(VecSet(fglobal, 0.)); 10152 PetscCall(VecSet(fglobalo, 0.)); 10153 PetscCall(VecSet(flocal, 0.)); 10154 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10155 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10156 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10157 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10158 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10159 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10160 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10161 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10162 *shift = fglobal; 10163 PetscCall(VecDestroy(&flocal)); 10164 PetscCall(VecDestroy(&fglobalo)); 10165 PetscCall(VecDestroy(&clocal)); 10166 PetscCall(VecDestroy(&cglobalo)); 10167 PetscCall(VecDestroy(&rscale)); 10168 PetscCall(MatDestroy(&interpo)); 10169 PetscCall(DMDestroy(&dmfo)); 10170 PetscCall(DMDestroy(&dmco)); 10171 PetscFunctionReturn(PETSC_SUCCESS); 10172 } 10173 10174 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10175 { 10176 PetscObject shifto; 10177 Vec shift; 10178 10179 PetscFunctionBegin; 10180 if (!interp) { 10181 Vec rscale; 10182 10183 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10184 PetscCall(VecDestroy(&rscale)); 10185 } else { 10186 PetscCall(PetscObjectReference((PetscObject)interp)); 10187 } 10188 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10189 if (!shifto) { 10190 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10191 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10192 shifto = (PetscObject)shift; 10193 PetscCall(VecDestroy(&shift)); 10194 } 10195 shift = (Vec)shifto; 10196 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10197 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10198 PetscCall(MatDestroy(&interp)); 10199 PetscFunctionReturn(PETSC_SUCCESS); 10200 } 10201 10202 /* Pointwise interpolation 10203 Just code FEM for now 10204 u^f = I u^c 10205 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10206 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10207 I_{ij} = psi^f_i phi^c_j 10208 */ 10209 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10210 { 10211 PetscSection gsc, gsf; 10212 PetscInt m, n; 10213 void *ctx; 10214 DM cdm; 10215 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10216 10217 PetscFunctionBegin; 10218 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10219 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10220 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10221 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10222 10223 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10224 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10225 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10226 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10227 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10228 10229 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10230 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10231 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10232 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10233 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10234 if (scaling) { 10235 /* Use naive scaling */ 10236 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10237 } 10238 PetscFunctionReturn(PETSC_SUCCESS); 10239 } 10240 10241 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10242 { 10243 VecScatter ctx; 10244 10245 PetscFunctionBegin; 10246 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10247 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10248 PetscCall(VecScatterDestroy(&ctx)); 10249 PetscFunctionReturn(PETSC_SUCCESS); 10250 } 10251 10252 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[]) 10253 { 10254 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10255 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10256 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10257 } 10258 10259 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10260 { 10261 DM dmc; 10262 PetscDS ds; 10263 Vec ones, locmass; 10264 IS cellIS; 10265 PetscFormKey key; 10266 PetscInt depth; 10267 10268 PetscFunctionBegin; 10269 PetscCall(DMClone(dm, &dmc)); 10270 PetscCall(DMCopyDisc(dm, dmc)); 10271 PetscCall(DMGetDS(dmc, &ds)); 10272 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10273 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10274 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10275 else PetscCall(DMGetLocalVector(dm, &locmass)); 10276 PetscCall(DMGetLocalVector(dm, &ones)); 10277 PetscCall(DMPlexGetDepth(dm, &depth)); 10278 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10279 PetscCall(VecSet(locmass, 0.0)); 10280 PetscCall(VecSet(ones, 1.0)); 10281 key.label = NULL; 10282 key.value = 0; 10283 key.field = 0; 10284 key.part = 0; 10285 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10286 PetscCall(ISDestroy(&cellIS)); 10287 if (mass) { 10288 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10289 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10290 } 10291 PetscCall(DMRestoreLocalVector(dm, &ones)); 10292 if (lmass) *lmass = locmass; 10293 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10294 PetscCall(DMDestroy(&dmc)); 10295 PetscFunctionReturn(PETSC_SUCCESS); 10296 } 10297 10298 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10299 { 10300 PetscSection gsc, gsf; 10301 PetscInt m, n; 10302 void *ctx; 10303 DM cdm; 10304 PetscBool regular; 10305 10306 PetscFunctionBegin; 10307 if (dmFine == dmCoarse) { 10308 DM dmc; 10309 PetscDS ds; 10310 PetscWeakForm wf; 10311 Vec u; 10312 IS cellIS; 10313 PetscFormKey key; 10314 PetscInt depth; 10315 10316 PetscCall(DMClone(dmFine, &dmc)); 10317 PetscCall(DMCopyDisc(dmFine, dmc)); 10318 PetscCall(DMGetDS(dmc, &ds)); 10319 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10320 PetscCall(PetscWeakFormClear(wf)); 10321 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10322 PetscCall(DMCreateMatrix(dmc, mass)); 10323 PetscCall(DMGetLocalVector(dmc, &u)); 10324 PetscCall(DMPlexGetDepth(dmc, &depth)); 10325 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10326 PetscCall(MatZeroEntries(*mass)); 10327 key.label = NULL; 10328 key.value = 0; 10329 key.field = 0; 10330 key.part = 0; 10331 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10332 PetscCall(ISDestroy(&cellIS)); 10333 PetscCall(DMRestoreLocalVector(dmc, &u)); 10334 PetscCall(DMDestroy(&dmc)); 10335 } else { 10336 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10337 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10338 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10339 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10340 10341 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10342 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10343 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10344 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10345 10346 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10347 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10348 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10349 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10350 } 10351 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10352 PetscFunctionReturn(PETSC_SUCCESS); 10353 } 10354 10355 /*@ 10356 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10357 10358 Input Parameter: 10359 . dm - The `DMPLEX` object 10360 10361 Output Parameter: 10362 . regular - The flag 10363 10364 Level: intermediate 10365 10366 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10367 @*/ 10368 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10369 { 10370 PetscFunctionBegin; 10371 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10372 PetscAssertPointer(regular, 2); 10373 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10374 PetscFunctionReturn(PETSC_SUCCESS); 10375 } 10376 10377 /*@ 10378 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10379 10380 Input Parameters: 10381 + dm - The `DMPLEX` object 10382 - regular - The flag 10383 10384 Level: intermediate 10385 10386 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10387 @*/ 10388 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10389 { 10390 PetscFunctionBegin; 10391 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10392 ((DM_Plex *)dm->data)->regularRefinement = regular; 10393 PetscFunctionReturn(PETSC_SUCCESS); 10394 } 10395 10396 /*@ 10397 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10398 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10399 10400 Not Collective 10401 10402 Input Parameter: 10403 . dm - The `DMPLEX` object 10404 10405 Output Parameters: 10406 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10407 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10408 10409 Level: intermediate 10410 10411 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10412 @*/ 10413 PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS) 10414 { 10415 DM_Plex *plex = (DM_Plex *)dm->data; 10416 10417 PetscFunctionBegin; 10418 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10419 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10420 if (anchorSection) *anchorSection = plex->anchorSection; 10421 if (anchorIS) *anchorIS = plex->anchorIS; 10422 PetscFunctionReturn(PETSC_SUCCESS); 10423 } 10424 10425 /*@ 10426 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10427 10428 Collective 10429 10430 Input Parameters: 10431 + dm - The `DMPLEX` object 10432 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10433 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10434 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10435 10436 Level: intermediate 10437 10438 Notes: 10439 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10440 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10441 combination of other points' degrees of freedom. 10442 10443 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10444 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10445 10446 The reference counts of `anchorSection` and `anchorIS` are incremented. 10447 10448 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10449 @*/ 10450 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10451 { 10452 DM_Plex *plex = (DM_Plex *)dm->data; 10453 PetscMPIInt result; 10454 10455 PetscFunctionBegin; 10456 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10457 if (anchorSection) { 10458 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10459 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10460 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10461 } 10462 if (anchorIS) { 10463 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10464 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10465 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10466 } 10467 10468 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10469 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10470 plex->anchorSection = anchorSection; 10471 10472 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10473 PetscCall(ISDestroy(&plex->anchorIS)); 10474 plex->anchorIS = anchorIS; 10475 10476 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10477 PetscInt size, a, pStart, pEnd; 10478 const PetscInt *anchors; 10479 10480 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10481 PetscCall(ISGetLocalSize(anchorIS, &size)); 10482 PetscCall(ISGetIndices(anchorIS, &anchors)); 10483 for (a = 0; a < size; a++) { 10484 PetscInt p; 10485 10486 p = anchors[a]; 10487 if (p >= pStart && p < pEnd) { 10488 PetscInt dof; 10489 10490 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10491 if (dof) { 10492 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10493 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10494 } 10495 } 10496 } 10497 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10498 } 10499 /* reset the generic constraints */ 10500 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10501 PetscFunctionReturn(PETSC_SUCCESS); 10502 } 10503 10504 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10505 { 10506 PetscSection anchorSection; 10507 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10508 10509 PetscFunctionBegin; 10510 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10511 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10512 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10513 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10514 if (numFields) { 10515 PetscInt f; 10516 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10517 10518 for (f = 0; f < numFields; f++) { 10519 PetscInt numComp; 10520 10521 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10522 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10523 } 10524 } 10525 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10526 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10527 pStart = PetscMax(pStart, sStart); 10528 pEnd = PetscMin(pEnd, sEnd); 10529 pEnd = PetscMax(pStart, pEnd); 10530 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10531 for (p = pStart; p < pEnd; p++) { 10532 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10533 if (dof) { 10534 PetscCall(PetscSectionGetDof(section, p, &dof)); 10535 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10536 for (f = 0; f < numFields; f++) { 10537 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10538 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10539 } 10540 } 10541 } 10542 PetscCall(PetscSectionSetUp(*cSec)); 10543 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10544 PetscFunctionReturn(PETSC_SUCCESS); 10545 } 10546 10547 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10548 { 10549 PetscSection aSec; 10550 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10551 const PetscInt *anchors; 10552 PetscInt numFields, f; 10553 IS aIS; 10554 MatType mtype; 10555 PetscBool iscuda, iskokkos; 10556 10557 PetscFunctionBegin; 10558 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10559 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10560 PetscCall(PetscSectionGetStorageSize(section, &n)); 10561 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10562 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10563 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10564 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10565 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10566 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10567 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10568 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10569 else mtype = MATSEQAIJ; 10570 PetscCall(MatSetType(*cMat, mtype)); 10571 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10572 PetscCall(ISGetIndices(aIS, &anchors)); 10573 /* cSec will be a subset of aSec and section */ 10574 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10575 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10576 PetscCall(PetscMalloc1(m + 1, &i)); 10577 i[0] = 0; 10578 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10579 for (p = pStart; p < pEnd; p++) { 10580 PetscInt rDof, rOff, r; 10581 10582 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10583 if (!rDof) continue; 10584 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10585 if (numFields) { 10586 for (f = 0; f < numFields; f++) { 10587 annz = 0; 10588 for (r = 0; r < rDof; r++) { 10589 a = anchors[rOff + r]; 10590 if (a < sStart || a >= sEnd) continue; 10591 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10592 annz += aDof; 10593 } 10594 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10595 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10596 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10597 } 10598 } else { 10599 annz = 0; 10600 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10601 for (q = 0; q < dof; q++) { 10602 a = anchors[rOff + q]; 10603 if (a < sStart || a >= sEnd) continue; 10604 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10605 annz += aDof; 10606 } 10607 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10608 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10609 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10610 } 10611 } 10612 nnz = i[m]; 10613 PetscCall(PetscMalloc1(nnz, &j)); 10614 offset = 0; 10615 for (p = pStart; p < pEnd; p++) { 10616 if (numFields) { 10617 for (f = 0; f < numFields; f++) { 10618 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10619 for (q = 0; q < dof; q++) { 10620 PetscInt rDof, rOff, r; 10621 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10622 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10623 for (r = 0; r < rDof; r++) { 10624 PetscInt s; 10625 10626 a = anchors[rOff + r]; 10627 if (a < sStart || a >= sEnd) continue; 10628 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10629 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10630 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10631 } 10632 } 10633 } 10634 } else { 10635 PetscCall(PetscSectionGetDof(cSec, p, &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(PetscSectionGetDof(section, a, &aDof)); 10646 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10647 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10648 } 10649 } 10650 } 10651 } 10652 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10653 PetscCall(PetscFree(i)); 10654 PetscCall(PetscFree(j)); 10655 PetscCall(ISRestoreIndices(aIS, &anchors)); 10656 PetscFunctionReturn(PETSC_SUCCESS); 10657 } 10658 10659 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10660 { 10661 DM_Plex *plex = (DM_Plex *)dm->data; 10662 PetscSection anchorSection, section, cSec; 10663 Mat cMat; 10664 10665 PetscFunctionBegin; 10666 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10667 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10668 if (anchorSection) { 10669 PetscInt Nf; 10670 10671 PetscCall(DMGetLocalSection(dm, §ion)); 10672 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10673 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10674 PetscCall(DMGetNumFields(dm, &Nf)); 10675 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10676 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10677 PetscCall(PetscSectionDestroy(&cSec)); 10678 PetscCall(MatDestroy(&cMat)); 10679 } 10680 PetscFunctionReturn(PETSC_SUCCESS); 10681 } 10682 10683 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10684 { 10685 IS subis; 10686 PetscSection section, subsection; 10687 10688 PetscFunctionBegin; 10689 PetscCall(DMGetLocalSection(dm, §ion)); 10690 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10691 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10692 /* Create subdomain */ 10693 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10694 /* Create submodel */ 10695 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10696 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10697 PetscCall(DMSetLocalSection(*subdm, subsection)); 10698 PetscCall(PetscSectionDestroy(&subsection)); 10699 PetscCall(DMCopyDisc(dm, *subdm)); 10700 /* Create map from submodel to global model */ 10701 if (is) { 10702 PetscSection sectionGlobal, subsectionGlobal; 10703 IS spIS; 10704 const PetscInt *spmap; 10705 PetscInt *subIndices; 10706 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10707 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10708 10709 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10710 PetscCall(ISGetIndices(spIS, &spmap)); 10711 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10712 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10713 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10714 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10715 for (p = pStart; p < pEnd; ++p) { 10716 PetscInt gdof, pSubSize = 0; 10717 10718 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10719 if (gdof > 0) { 10720 for (f = 0; f < Nf; ++f) { 10721 PetscInt fdof, fcdof; 10722 10723 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10724 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10725 pSubSize += fdof - fcdof; 10726 } 10727 subSize += pSubSize; 10728 if (pSubSize) { 10729 if (bs < 0) { 10730 bs = pSubSize; 10731 } else if (bs != pSubSize) { 10732 /* Layout does not admit a pointwise block size */ 10733 bs = 1; 10734 } 10735 } 10736 } 10737 } 10738 /* Must have same blocksize on all procs (some might have no points) */ 10739 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10740 bsLocal[1] = bs; 10741 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10742 if (bsMinMax[0] != bsMinMax[1]) { 10743 bs = 1; 10744 } else { 10745 bs = bsMinMax[0]; 10746 } 10747 PetscCall(PetscMalloc1(subSize, &subIndices)); 10748 for (p = pStart; p < pEnd; ++p) { 10749 PetscInt gdof, goff; 10750 10751 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10752 if (gdof > 0) { 10753 const PetscInt point = spmap[p]; 10754 10755 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10756 for (f = 0; f < Nf; ++f) { 10757 PetscInt fdof, fcdof, fc, f2, poff = 0; 10758 10759 /* Can get rid of this loop by storing field information in the global section */ 10760 for (f2 = 0; f2 < f; ++f2) { 10761 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10762 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10763 poff += fdof - fcdof; 10764 } 10765 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10766 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10767 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10768 } 10769 } 10770 } 10771 PetscCall(ISRestoreIndices(spIS, &spmap)); 10772 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10773 if (bs > 1) { 10774 /* We need to check that the block size does not come from non-contiguous fields */ 10775 PetscInt i, j, set = 1; 10776 for (i = 0; i < subSize; i += bs) { 10777 for (j = 0; j < bs; ++j) { 10778 if (subIndices[i + j] != subIndices[i] + j) { 10779 set = 0; 10780 break; 10781 } 10782 } 10783 } 10784 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10785 } 10786 /* Attach nullspace */ 10787 for (f = 0; f < Nf; ++f) { 10788 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10789 if ((*subdm)->nullspaceConstructors[f]) break; 10790 } 10791 if (f < Nf) { 10792 MatNullSpace nullSpace; 10793 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10794 10795 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10796 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10797 } 10798 } 10799 PetscFunctionReturn(PETSC_SUCCESS); 10800 } 10801 10802 /*@ 10803 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10804 10805 Input Parameters: 10806 + dm - The `DM` 10807 - dummy - unused argument 10808 10809 Options Database Key: 10810 . -dm_plex_monitor_throughput - Activate the monitor 10811 10812 Level: developer 10813 10814 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10815 @*/ 10816 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10817 { 10818 PetscLogHandler default_handler; 10819 10820 PetscFunctionBegin; 10821 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10822 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10823 if (default_handler) { 10824 PetscLogEvent event; 10825 PetscEventPerfInfo eventInfo; 10826 PetscLogDouble cellRate, flopRate; 10827 PetscInt cStart, cEnd, Nf, N; 10828 const char *name; 10829 10830 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10831 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10832 PetscCall(DMGetNumFields(dm, &Nf)); 10833 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10834 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10835 N = (cEnd - cStart) * Nf * eventInfo.count; 10836 flopRate = eventInfo.flops / eventInfo.time; 10837 cellRate = N / eventInfo.time; 10838 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)); 10839 } else { 10840 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."); 10841 } 10842 PetscFunctionReturn(PETSC_SUCCESS); 10843 } 10844